Skip to content

Commit a3811b8

Browse files
authored
Merge pull request #1075 from pimoroni/feature/python-linting-update
QA/CI: Update and apply Python and MicroPython linting rules.
2 parents 5346038 + 4ebdff4 commit a3811b8

File tree

276 files changed

+727
-21773
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

276 files changed

+727
-21773
lines changed

.github/workflows/python.yml

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Python
1+
name: Python Linting
22

33
on:
44
push:
@@ -7,24 +7,26 @@ on:
77
jobs:
88
build:
99
name: Python Linting
10-
runs-on: ubuntu-20.04
10+
runs-on: ubuntu-24.04
1111
steps:
1212
- uses: actions/checkout@v4
1313

14+
- name: Install Python
15+
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55
16+
with:
17+
python-version: '3.13'
18+
1419
- name: Install Python Deps
15-
run: python3 -m pip install flake8
20+
run: source ci/python.sh && qa_prepare_all
1621

17-
- name: Lint micropython/modules_py
22+
- name: Lint MicroPython Examples
1823
shell: bash
19-
run: |
20-
python3 -m flake8 --show-source --ignore E501 micropython/modules_py
24+
run: source ci/python.sh && qa_examples_check
2125

22-
- name: Lint micropython/examples
26+
- name: Lint MicroPython Modules
2327
shell: bash
24-
run: |
25-
python3 -m flake8 --show-source --ignore E501 micropython/examples
28+
run: source ci/python.sh && qa_modules_check
2629

27-
- name: Lint .py tools in C++ examples
30+
- name: Lint Python Tools
2831
shell: bash
29-
run: |
30-
python3 -m flake8 --show-source --ignore E501 examples
32+
run: source ci/python.sh && qa_tools_check

ci/python.sh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Include:
2+
# F = Pyflakes
3+
# Q = Quotes
4+
# E/W = pycodestyle (Whitespace, Line lengths etc)
5+
# B - flake8-bugbear = Unused loop variables, sloppy code
6+
# COM - flake8-commas
7+
# BLE - flake8-blind-except
8+
# C4 - flake8-comprehensions
9+
# ISC - flake8-implicit-str-concat = Implicit string concat, eg: `"hello" "world"` on one line
10+
# ICN - flake8-import-conventions = Import conventions
11+
# PIE - flake8-pie = Misc silliness, catches range with a 0 start argument
12+
# RET - flake8-return = Enforces straight-forward code around return statements
13+
# SLF - flake8-self
14+
# ARG - flake8-unused-arguments
15+
16+
# Ignore:
17+
# E501 - "line too long". How narrow is your screen!?
18+
# E402 - "module level import not at top of file". Needs must!
19+
# COM812 - "Add trailing comma". These are a little obnoxious and weird.
20+
# ICN001 - "numpy should be imported as np". No. No it should not.
21+
22+
QA_INCLUDE="F,Q,W,E,B,COM,BLE,C4,ISC,ICN,PIE,RSE,RET,SLF,ARG"
23+
QA_IGNORE="E501,E402,COM812,ICN001"
24+
QA_EXCLUDE="micropython/examples/common/lib/tinyweb/server.py,micropython/examples/pico_wireless/*"
25+
26+
function qa_prepare_all {
27+
pip install ruff
28+
}
29+
30+
function qa_check {
31+
ruff check --select "$QA_INCLUDE" --ignore "$QA_IGNORE" --exclude "$QA_EXCLUDE" "$1"
32+
}
33+
34+
function qa_fix {
35+
ruff check --select "$QA_INCLUDE" --ignore "$QA_IGNORE" --exclude "$QA_EXCLUDE" --fix "$1"
36+
}
37+
38+
function qa_examples_check {
39+
qa_check micropython/examples
40+
}
41+
42+
function qa_examples_fix {
43+
qa_fix micropython/examples
44+
}
45+
46+
function qa_modules_check {
47+
qa_check micropython/modules_py
48+
}
49+
50+
function qa_modules_fix {
51+
qa_fix micropython/modules_py
52+
}
53+
54+
function qa_tools_check {
55+
qa_check examples
56+
}
57+
58+
function qa_tools_fix {
59+
qa_fix examples
60+
}

examples/badger2040/hershey_font_converter/convert.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def convert_font(data):
7272
while data.find("\n", char_data_len) != -1:
7373
data = data.replace("\n", "", 1)
7474

75-
for i in range(0, vertex_count):
75+
for i in range(vertex_count):
7676
offset = 10 + (i * 2)
7777
if data[offset:offset + 2] == " R":
7878
# pen up for one
@@ -106,7 +106,7 @@ def convert_font(data):
106106
# int8_t *vertices; // vertex data (indices: even = x, odd = y)
107107
# };
108108
chars = []
109-
for i in range(0, 95):
109+
for i in range(95):
110110
if i in char_data:
111111
chars.append(
112112
" {{.width={width}, .vertex_count={vertex_count}, .vertices=&{font_name}_vertices[{offset}]}}".format(

examples/badger2040/image_converter/convert.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ def data():
2828
"""
2929

3030

31-
parser = argparse.ArgumentParser(description='Converts images into the format used by Badger2040.')
32-
parser.add_argument('file', nargs="+", help='input files to convert')
33-
parser.add_argument('--out_dir', type=Path, default=None, help='output directory')
34-
parser.add_argument('--binary', action="store_true", help='output binary file for MicroPython')
35-
parser.add_argument('--py', action="store_true", help='output .py file for MicroPython embedding')
36-
parser.add_argument('--resize', action="store_true", help='force images to 296x128 pixels')
31+
parser = argparse.ArgumentParser(description="Converts images into the format used by Badger2040.")
32+
parser.add_argument("file", nargs="+", help="input files to convert")
33+
parser.add_argument("--out_dir", type=Path, default=None, help="output directory")
34+
parser.add_argument("--binary", action="store_true", help="output binary file for MicroPython")
35+
parser.add_argument("--py", action="store_true", help="output .py file for MicroPython embedding")
36+
parser.add_argument("--resize", action="store_true", help="force images to 296x128 pixels")
3737

3838
options = parser.parse_args()
3939

@@ -43,7 +43,7 @@ class ByteWriter(object):
4343

4444
def __init__(self, stream, varname):
4545
self.stream = stream
46-
self.stream.write('{} =\\\n'.format(varname))
46+
self.stream.write("{} =\\\n".format(varname))
4747
self.bytecount = 0 # For line breaks
4848

4949
def _eol(self):
@@ -59,7 +59,7 @@ def _bol(self):
5959
def obyte(self, data):
6060
if not self.bytecount:
6161
self._bol()
62-
self.stream.write('\\x{:02x}'.format(data))
62+
self.stream.write("\\x{:02x}".format(data))
6363
self.bytecount += 1
6464
self.bytecount %= self.bytes_per_line
6565
if not self.bytecount:
@@ -74,7 +74,7 @@ def odata(self, bytelist):
7474
def eot(self): # User force EOL if one hasn't occurred
7575
if self.bytecount:
7676
self._eot()
77-
self.stream.write('\n')
77+
self.stream.write("\n")
7878

7979

8080
def convert_image(img):
@@ -85,15 +85,14 @@ def convert_image(img):
8585
img = enhancer.enhance(2.0)
8686
except ValueError:
8787
pass
88-
img = img.convert("1") # convert to black and white
89-
return img
88+
return img.convert("1") # convert to black and white
9089

9190

9291
def write_stream(header, footer, ip_stream, op_stream):
9392
op_stream.write(header)
94-
op_stream.write('\n')
93+
op_stream.write("\n")
9594
data = ip_stream.read()
96-
bw_data = ByteWriter(op_stream, '_data')
95+
bw_data = ByteWriter(op_stream, "_data")
9796
bw_data.odata(data)
9897
bw_data.eot()
9998
op_stream.write(footer)
@@ -127,10 +126,10 @@ def write_stream(header, footer, ip_stream, op_stream):
127126
with open(output_filename, "w") as out:
128127
write_stream(PY_HEADER, PY_FOOTER, io.BytesIO(bytes(output_data)), out)
129128
else:
130-
image_code = '''\
129+
image_code = """\
131130
static const uint8_t {image_name}[{count}] = {{
132131
{byte_data}
133132
}};
134-
'''.format(image_name=image_name, count=len(output_data), byte_data=", ".join(str(b) for b in output_data))
133+
""".format(image_name=image_name, count=len(output_data), byte_data=", ".join(str(b) for b in output_data))
135134

136135
print(image_code)

examples/badger2040/image_converter/data_to_py.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class ByteWriter(object):
4141

4242
def __init__(self, stream, varname):
4343
self.stream = stream
44-
self.stream.write('{} =\\\n'.format(varname))
44+
self.stream.write("{} =\\\n".format(varname))
4545
self.bytecount = 0 # For line breaks
4646

4747
def _eol(self):
@@ -57,7 +57,7 @@ def _bol(self):
5757
def obyte(self, data):
5858
if not self.bytecount:
5959
self._bol()
60-
self.stream.write('\\x{:02x}'.format(data))
60+
self.stream.write("\\x{:02x}".format(data))
6161
self.bytecount += 1
6262
self.bytecount %= self.bytes_per_line
6363
if not self.bytecount:
@@ -72,7 +72,7 @@ def odata(self, bytelist):
7272
def eot(self): # User force EOL if one hasn't occurred
7373
if self.bytecount:
7474
self._eot()
75-
self.stream.write('\n')
75+
self.stream.write("\n")
7676

7777

7878
# PYTHON FILE WRITING
@@ -90,17 +90,17 @@ def data():
9090

9191

9292
def write_func(stream, name, arg):
93-
stream.write('def {}():\n return {}\n\n'.format(name, arg))
93+
stream.write("def {}():\n return {}\n\n".format(name, arg))
9494

9595

9696
def write_data(op_path, ip_path):
9797
try:
98-
with open(ip_path, 'rb') as ip_stream:
98+
with open(ip_path, "rb") as ip_stream:
9999
try:
100-
with open(op_path, 'w') as op_stream:
100+
with open(op_path, "w") as op_stream:
101101
write_stream(ip_stream, op_stream)
102102
except OSError:
103-
print("Can't open", op_path, 'for writing')
103+
print("Can't open", op_path, "for writing")
104104
return False
105105
except OSError:
106106
print("Can't open", ip_path)
@@ -110,9 +110,9 @@ def write_data(op_path, ip_path):
110110

111111
def write_stream(ip_stream, op_stream):
112112
op_stream.write(STR01)
113-
op_stream.write('\n')
113+
op_stream.write("\n")
114114
data = ip_stream.read()
115-
bw_data = ByteWriter(op_stream, '_data')
115+
bw_data = ByteWriter(op_stream, "_data")
116116
bw_data.odata(data)
117117
bw_data.eot()
118118
op_stream.write(STR02)
@@ -135,20 +135,20 @@ def quit(msg):
135135
if __name__ == "__main__":
136136
parser = argparse.ArgumentParser(__file__, description=DESC,
137137
formatter_class=argparse.RawDescriptionHelpFormatter)
138-
parser.add_argument('infile', type=str, help='Input file path')
139-
parser.add_argument('outfile', type=str,
140-
help='Path and name of output file. Must have .py extension.')
138+
parser.add_argument("infile", type=str, help="Input file path")
139+
parser.add_argument("outfile", type=str,
140+
help="Path and name of output file. Must have .py extension.")
141141

142142
args = parser.parse_args()
143143

144144
if not os.path.isfile(args.infile):
145145
quit("Data filename does not exist")
146146

147-
if not os.path.splitext(args.outfile)[1].upper() == '.PY':
148-
quit('Output filename must have a .py extension.')
147+
if not os.path.splitext(args.outfile)[1].upper() == ".PY":
148+
quit("Output filename must have a .py extension.")
149149

150-
print('Writing Python file.')
150+
print("Writing Python file.")
151151
if not write_data(args.outfile, args.infile):
152152
sys.exit(1)
153153

154-
print(args.outfile, 'written successfully.')
154+
print(args.outfile, "written successfully.")

0 commit comments

Comments
 (0)