Skip to content

Commit 0a235e3

Browse files
authored
Merge pull request #16 from makermelissa/main
Fixed an issue with run_command() sometimes locking up
2 parents c658112 + 7c8bedc commit 0a235e3

File tree

2 files changed

+55
-90
lines changed

2 files changed

+55
-90
lines changed

.pylintrc

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
# run arbitrary code
1010
extension-pkg-whitelist=
1111

12-
# Add files or directories to the blacklist. They should be base names, not
12+
# Add files or directories to the ignore-list. They should be base names, not
1313
# paths.
1414
ignore=CVS
1515

16-
# Add files or directories matching the regex patterns to the blacklist. The
16+
# Add files or directories matching the regex patterns to the ignore-list. The
1717
# regex matches against base names, not paths.
1818
ignore-patterns=
1919

@@ -22,12 +22,11 @@ ignore-patterns=
2222
#init-hook=
2323

2424
# Use multiple processes to speed up Pylint.
25-
# jobs=1
26-
jobs=2
25+
jobs=1
2726

2827
# List of plugins (as comma separated values of python modules names) to load,
2928
# usually to register additional checkers.
30-
load-plugins=
29+
load-plugins=pylint.extensions.no_self_use
3130

3231
# Pickle collected data for later comparisons.
3332
persistent=yes
@@ -55,8 +54,8 @@ confidence=
5554
# --enable=similarities". If you want to run only the classes checker, but have
5655
# no Warning level messages displayed, use"--disable=all --enable=classes
5756
# --disable=W"
58-
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
59-
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation
57+
# disable=import-error,raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,deprecated-str-translate-call
58+
disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding
6059

6160
# Enable the message, report, category or checker with the given id(s). You can
6261
# either give multiple identifier separated by comma (,) or put this option
@@ -226,12 +225,6 @@ max-line-length=100
226225
# Maximum number of lines in a module
227226
max-module-lines=1000
228227

229-
# List of optional constructs for which whitespace checking is disabled. `dict-
230-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
231-
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
232-
# `empty-line` allows space-only lines.
233-
no-space-check=trailing-comma,dict-separator
234-
235228
# Allow the body of a class to be on the same line as the declaration if body
236229
# contains single statement.
237230
single-line-class-stmt=no
@@ -250,56 +243,37 @@ ignore-comments=yes
250243
ignore-docstrings=yes
251244

252245
# Ignore imports when computing similarities.
253-
ignore-imports=no
246+
ignore-imports=yes
254247

255248
# Minimum lines number of a similarity.
256-
min-similarity-lines=4
249+
min-similarity-lines=12
257250

258251

259252
[BASIC]
260253

261-
# Naming hint for argument names
262-
argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
263-
264254
# Regular expression matching correct argument names
265255
argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
266256

267-
# Naming hint for attribute names
268-
attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
269-
270257
# Regular expression matching correct attribute names
271258
attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
272259

273260
# Bad variable names which should always be refused, separated by a comma
274261
bad-names=foo,bar,baz,toto,tutu,tata
275262

276-
# Naming hint for class attribute names
277-
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
278-
279263
# Regular expression matching correct class attribute names
280264
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
281265

282-
# Naming hint for class names
283-
# class-name-hint=[A-Z_][a-zA-Z0-9]+$
284-
class-name-hint=[A-Z_][a-zA-Z0-9_]+$
285-
286266
# Regular expression matching correct class names
287267
# class-rgx=[A-Z_][a-zA-Z0-9]+$
288268
class-rgx=[A-Z_][a-zA-Z0-9_]+$
289269

290-
# Naming hint for constant names
291-
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
292-
293270
# Regular expression matching correct constant names
294271
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
295272

296273
# Minimum line length for functions/classes that require docstrings, shorter
297274
# ones are exempt.
298275
docstring-min-length=-1
299276

300-
# Naming hint for function names
301-
function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
302-
303277
# Regular expression matching correct function names
304278
function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
305279

@@ -310,21 +284,12 @@ good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_
310284
# Include a hint for the correct naming format with invalid-name
311285
include-naming-hint=no
312286

313-
# Naming hint for inline iteration names
314-
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
315-
316287
# Regular expression matching correct inline iteration names
317288
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
318289

319-
# Naming hint for method names
320-
method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
321-
322290
# Regular expression matching correct method names
323291
method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
324292

325-
# Naming hint for module names
326-
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
327-
328293
# Regular expression matching correct module names
329294
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
330295

@@ -340,9 +305,6 @@ no-docstring-rgx=^_
340305
# to this list to register other decorators that produce valid properties.
341306
property-classes=abc.abstractproperty
342307

343-
# Naming hint for variable names
344-
variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
345-
346308
# Regular expression matching correct variable names
347309
variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
348310

adafruit_shell.py

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import os
2626
import shutil
2727
import subprocess
28+
import fcntl
2829
import platform
2930
import fileinput
3031
import re
@@ -67,75 +68,77 @@ def run_command(self, cmd, suppress_message=False, return_output=False):
6768
"""
6869
Run a shell command and show the output as it runs
6970
"""
70-
original_stdout = sys.stdout
71-
original_stderr = sys.stderr
72-
try:
73-
# pylint: disable=consider-using-with
74-
proc = subprocess.Popen(
75-
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
76-
)
77-
# pylint: enable=consider-using-with
78-
full_output = ""
79-
while True:
80-
output = proc.stdout.readline()
81-
err = proc.stderr.read()
82-
if err and not suppress_message:
83-
self.error(err.decode("utf-8", errors="ignore"))
84-
if len(output) == 0 and proc.poll() is not None:
85-
break
86-
if output:
87-
decoded_output = output.decode("utf-8", errors="ignore").strip()
88-
if not suppress_message:
89-
self.info(decoded_output)
90-
full_output += decoded_output
91-
except Exception: # pylint: disable=broad-except
92-
pass
93-
finally:
94-
sys.stdout = original_stdout
95-
sys.stderr = original_stderr
96-
if return_output:
97-
return full_output
98-
r = proc.poll()
99-
if r == 0:
71+
72+
def read_stream(output):
73+
file_descriptor = output.fileno()
74+
file_flags = fcntl.fcntl(file_descriptor, fcntl.F_GETFL)
75+
fcntl.fcntl(file_descriptor, fcntl.F_SETFL, file_flags | os.O_NONBLOCK)
76+
try:
77+
return output.read()
78+
except TypeError:
79+
return ""
80+
81+
full_output = ""
82+
with subprocess.Popen(
83+
cmd,
84+
shell=True,
85+
stdout=subprocess.PIPE,
86+
stderr=subprocess.PIPE,
87+
universal_newlines=True,
88+
) as proc:
89+
while proc.poll() is None:
90+
err = read_stream(proc.stderr)
91+
if err != "" and not suppress_message:
92+
self.error(err.strip(), end="\n\r")
93+
output = read_stream(proc.stdout)
94+
if output != "" and not suppress_message:
95+
self.info(output.strip(), end="\n\r")
96+
full_output += output
97+
return_code = proc.poll()
98+
proc.stdout.close()
99+
proc.stderr.close()
100+
if return_output:
101+
return full_output
102+
if return_code:
103+
return False
100104
return True
101-
return False
102105

103-
def info(self, message):
106+
def info(self, message, **kwargs):
104107
"""
105108
Display a message with the group in green
106109
"""
107110
if self._group is not None:
108-
print(colored.green(self._group) + " " + message)
111+
print(colored.green(self._group) + " " + message, **kwargs)
109112
else:
110-
print(message)
113+
print(message, **kwargs)
111114

112-
def warn(self, message):
115+
def warn(self, message, **kwargs):
113116
"""
114117
Display a message with the group in yellow
115118
"""
116119
if self._group is not None:
117-
print(colored.yellow(self._group) + " " + message)
120+
print(colored.yellow(self._group) + " " + message, **kwargs)
118121
else:
119-
print(message)
122+
print(message, **kwargs)
120123

121-
def bail(self, message=None):
124+
def bail(self, message=None, **kwargs):
122125
"""
123126
Exit and display an error message if given
124127
"""
125128
if message is None:
126-
self.error("Exiting due to error")
129+
self.error("Exiting due to error", **kwargs)
127130
else:
128-
self.error(f"Exiting due to error: {message}")
131+
self.error(f"Exiting due to error: {message}", **kwargs)
129132
sys.exit(1)
130133

131-
def error(self, message):
134+
def error(self, message, **kwargs):
132135
"""
133-
Display some inforrmation
136+
Display some information
134137
"""
135138
if self._group is not None:
136-
print(colored.red(self._group) + " " + message)
139+
print(colored.red(self._group) + " " + message, **kwargs)
137140
else:
138-
print(message)
141+
print(message, **kwargs)
139142

140143
@staticmethod
141144
def print_colored(message, color):

0 commit comments

Comments
 (0)