Skip to content

Commit 8f48d0d

Browse files
Add Ruff and Basedpyright linters to (the newer) Python scripts in Mbed (#520)
* Add Ruff linter for Python scripts * Add to CI * Linting done! * Add basedpyright and start making fixes * More basedpyright progress * Passing pyright! * Fix a few more errors * Use types stubs * Eh just ignore for now * Tests and linting passing (locally!) * Pin typing extensions version * Augh, --unsafe-fixes got rid of my print statements! Dude! * Reformat * Muh print statements!!11!1 * Fix cast * Reformat * Respond to comments * Fix comment
1 parent 0b7b3a1 commit 8f48d0d

File tree

109 files changed

+1205
-2612
lines changed

Some content is hidden

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

109 files changed

+1205
-2612
lines changed

.github/workflows/basic_checks.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ jobs:
151151
run: |
152152
cd tools
153153
ruff format --diff
154+
155+
- name: Check Python Lint
156+
run: |
157+
cd tools
158+
ruff check --diff python/mbed_tools python/mbed_platformio
159+
basedpyright
154160
155161
156162
docs-check:

tools/pyproject.toml

Lines changed: 165 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ dependencies = [
2020
"jinja2>=2.11.3",
2121
"python-dotenv",
2222
"Click>=8.0", # Need at least this version for pathlib.Path support
23-
"GitPython",
2423
"tqdm",
2524
"tabulate",
2625
"requests>=2.20",
27-
"typing-extensions",
26+
"typing-extensions>=4.4.0",
2827
"pyserial",
2928
"appdirs",
3029
"pyjson5>=1.6",
@@ -34,12 +33,12 @@ dependencies = [
3433
# Needed for downloading CMSIS MCU descriptions
3534
"cmsis-pack-manager>=0.5.0",
3635

37-
# USB device detection on Mac
36+
# USB device detection on Windows
3837
"pywin32; platform_system=='Windows'",
3938

4039
# USB device detection on Linux
4140
"psutil; platform_system=='Linux'",
42-
"pyudev; platform_system=='Linux'",
41+
"pyudev>=0.24; platform_system=='Linux'", # 0.23.x seems to have issues with its Six dependency
4342

4443
# USB device detection on Mac
4544
"beautifulsoup4; sys_platform == 'darwin'",
@@ -72,7 +71,16 @@ unit-tests = [
7271
"lxml"
7372
]
7473
linters = [
75-
"ruff"
74+
"ruff",
75+
"basedpyright",
76+
77+
# To pass Pyright we need all the platform-dependent packages
78+
"platformio",
79+
"SCons",
80+
"psutil",
81+
"pyudev>=0.24",
82+
"beautifulsoup4",
83+
"lxml"
7684
]
7785
greentea = [
7886
## Additional requirements to install into the Mbed environment when running Greentea tests
@@ -109,4 +117,155 @@ ambiq_svl = "ambiq_svl.svl:cli"
109117

110118
[tool.ruff]
111119
line-length = 120
112-
src = ['python']
120+
src = ['python']
121+
122+
[tool.ruff.lint]
123+
select = [
124+
'A', # Builtins
125+
'ANN', # Annotations
126+
'ARG', # Unused arguments
127+
'B', # Bugbear
128+
'BLE', # Blind except
129+
'C4', # Comprehensions
130+
'C90', # mccabe
131+
'COM', # Commas
132+
'D2', # Docstring conventions
133+
'DTZ', # Datetimes
134+
'EM', # Error messages
135+
'ERA', # Commented-out code
136+
'EXE', # Executable
137+
'F', # Pyflakes
138+
'FA', # __future__ annotations
139+
'FLY', # F-strings
140+
'FURB', # Refurb
141+
'G', # Logging format
142+
'I', # Isort
143+
'ICN', # Import conventions
144+
'INP', # Disallow PEP-420 (Implicit namespace packages)
145+
'INT', # gettext
146+
'ISC', # Implicit str concat
147+
'LOG', # Logging
148+
'N', # PEP-8 Naming
149+
'NPY', # Numpy
150+
'PERF', # Unnecessary performance costs
151+
'PGH', # Pygrep hooks
152+
'PIE', # Unnecessary code
153+
'PL', # Pylint
154+
'PT', # Pytest
155+
'PTH', # Use Pathlib
156+
'PYI', # Stub files
157+
'Q', # Quotes
158+
'RET', # Return
159+
'RUF', # Ruff
160+
'RSE', # Raise
161+
'S', # Bandit
162+
'SIM', # Code simplification
163+
'SLF', # Private member access
164+
'SLOT', # __slots__
165+
'T10', # Debugger
166+
'T20', # Print
167+
'TCH', # Type checking
168+
'TID', # Tidy imports
169+
'TRY', # Exception handling
170+
'UP', # Pyupgrade
171+
'W', # Warnings
172+
'YTT', # sys.version
173+
]
174+
ignore = [
175+
'D203', # incorrect-blank-line-before-class
176+
'D212', # surrounding-whitespace
177+
'Q000', # bad-quotes-inline-string - Allow using single or double quotes
178+
'D200', # unnecessary-multiline-docstring
179+
'RET505', # superfluous-else-return
180+
'RET506', # superfluous-else-raise
181+
'TRY003', # raise-vanilla-args - Redundant with EM101
182+
'COM812', # missing-trailing-comma - incompatible with formatter
183+
'ISC001', # single-line-implicit-string-concatenation - incompatible with formatter
184+
'TRY300', # try-consider-else
185+
'PLR2004', # magic-value-comparison
186+
'SIM102', # collapsible-if - Sometimes it's nice for readability
187+
'PERF203', # try-except-in-loop - Sometimes this is needed!
188+
'PERF401', # manual-list-comprehension - Sometimes this makes code easier to understand.
189+
'PLR5501', # collapsible-else-if - Stop collapsing my if statements!
190+
'TC006', # runtime-cast-value
191+
'G004', # logging-f-string
192+
'ANN401', # any-type
193+
'DTZ005', # call-datetime-now-without-tzinfo - If this lint is enabled, it seems difficult to actually work with datetime objects that should be in the local time zone.
194+
'S701', # jinja2-autoescape-false - autoescape not needed because we are not rendering HTML
195+
'BLE001', # blind-except
196+
'S603', # subprocess-without-shell-equals-true - without disabling this, subprocess cannot be used at all!
197+
'ERA001', # commented-out-code
198+
'T201', # print
199+
200+
# For now allow old-style type annotations. Currently there's lots of code that uses them, and I am
201+
# not sure if there is a way to upgrade them automatically. And since this project still supports
202+
# back to Python 3.8, you can't actually use the new style of annotations without using the future annotations feature.
203+
"FA100", # future-rewritable-type-annotation
204+
"UP045", # non-pep604-annotation-optional
205+
"UP006", # non-pep585-annotation
206+
"UP007" # non-pep604-annotation-union
207+
]
208+
209+
# Allow "unsafe" fixes to be done automatically for the following:
210+
extend-safe-fixes = [
211+
"W291", # trailing-whitespace
212+
"W293", # blank-line-with-whitespace
213+
"EM101", # raw-string-in-exception
214+
"TC001", # typing-only-first-party-import
215+
"TC003", # typing-only-standard-library-import
216+
]
217+
218+
[tool.ruff.lint.mccabe]
219+
max-complexity = 15
220+
221+
[tool.ruff.lint.pylint]
222+
max-args = 10
223+
224+
[tool.ruff.lint.flake8-annotations]
225+
# Don't require a return type annotation for __init__ in most cases
226+
mypy-init-return = true
227+
228+
[tool.ruff.lint.isort]
229+
# Still fold imports onto one line if possible, even if the last import ends with a comma
230+
split-on-trailing-comma = false
231+
232+
[tool.basedpyright]
233+
234+
# Don't warn about things deprecated more recently than python 3.8
235+
pythonVersion = "3.8"
236+
237+
include = [
238+
"python/mbed_tools/**",
239+
"python/mbed_platformio/**"
240+
]
241+
242+
# For right now, we can configure basedpyright in relatively permissive mode.
243+
# We will allow code where the types of things are partially unknown, as there is
244+
# lots of legacy code in that category.
245+
# Also the PlatformIO code has to work with SCons, which is fundamentally type
246+
# annotation proof, so it can likely never pass these checks.
247+
reportUnknownVariableType = false
248+
reportUnknownMemberType = false
249+
reportUnknownLambdaType = false
250+
reportMissingTypeArgument = false
251+
reportUnknownArgumentType = false
252+
reportUnknownParameterType = false
253+
reportAny = false
254+
reportExplicitAny = false
255+
reportMissingTypeStubs = false
256+
257+
# Use "medium strict" member variable annotation rules, where the type checker
258+
# is allowed to infer the types of class variables based on what gets assigned in __init__
259+
reportIncompatibleUnannotatedOverride = true
260+
reportUnannotatedClassAttribute = false
261+
262+
# Conflicts with Ruff rules
263+
reportImplicitStringConcatenation = false
264+
265+
# Allow isinstance() even when it seems unneccessary based on type annotations.
266+
# This call is useful to check that the runtime types match the annotations.
267+
reportUnnecessaryIsInstance = false
268+
269+
# Some ignore comments are only needed on specific platforms, so failing due to unneeded ignore
270+
# comments creates an impossible situation
271+
reportUnnecessaryTypeIgnoreComment = false
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""
22
Copyright (c) 2025 Jamie Smith
3+
34
SPDX-License-Identifier: Apache-2.0
45
"""

0 commit comments

Comments
 (0)