Skip to content

Commit 5dda178

Browse files
authored
Improving ruff setup (#224)
* Redefining ruff, starting with target-version = "py38" Let's remove all rules so far, and re-introduce those by following the definitions of pylint. The first rule is target-version infered from the package definition that requires-python >= 3.8. * Excluding CSV and ref.*?py Patterns defined at .python-lint lines 10 & 14. * Disabling rules according to .python-lint Current setup defined between lines 57-105. * max-nested-blocks Defining `max-nested-blocks` as .pyhton-lint line 141. * Confirming with expected-line-ending-format While pylint defines `expected-line-ending-format`, ruff uses `line-ending` instead. Defined in .python-lint line 254. * Defining line-lenght as .python-lint line 267 * indent-width * multiple-statements-on-one-line-colon Equivalent to single-line-if-stmt at line 278 of .python-lint * task-tags In reference to notes, line 291 of .python-lint * In respect t ologging-modules, line 285 of .python-lint We don't need that with ruff, but here is a placeholder if we want to add more than default `logger` in the future. * unused imports Addressing "init-import=no" in line 402 from .python-lint * Defining max-args Interestingly, max-args is defined as 5 in line 434, but PLR0913 rule is ignored. * Defining DESIGN explicit setup To reflect DESIGN section in .python-lint, pages 431-463. * Closest option of satisfy EXCEPTIONS Ruff doesn't implement the exactly the same, but E722 is good enough if not even better. * Re-introducing all (W) Warning rules * Re-introducing (Q) flake8-quotes rules sup3r do not follow: - Q000 bad-quotes-inline-string - Q004 unnecessary-escaped-quote * Re-introducing (I) isort rules sup3r do not follow I001: unsorted-imports. * Re-introducing (NPY) NymPy-specific rules sup3r doesn't follow NPY002, but we might want to re-consider that in the future. * style: Conforming with UP039 * Re-introducing (UP) pyupgrade rules sup3r doesn't follow: - UP009: utf8-encoding-declaration - UP015: redundant-open-modes - UP032: f-string * Re-introducing (A) flake8-builtins sup3r doesn't conform with, but should reconsider that in the future: - A001: builtin-variable-shadowing - A002: builtin-argument-shadowing * Re-introducing (ARG) flake8-unused-arguments rules sup3r doesn't conform with: - ARG002: unused-method-argument - ARG003: unused-class-method-argument - ARG004: unused-static-method-argument - ARG005: unused-lambda-argument * Re-introducing (E) pycodestyle rules * Re-introducing (F) Pyflakes rules * Re-introducing (COM) flake8-commas rules sup3r doesn't conform with: - COM812: missing-trailing-comma * Introducing (N) pep8-naming rules sup3r doesn't conform with: - N802: invalid-function-name - N803: invalid-argument-name - N806: non-lowercase-variable-in-function * Introducing (D) pydocstyle rules sup3r doesn't conform with: - D105: undocumented-magic-method - D200: fits-on-one-line - D202: no-blank-line-after-function - D204: one-blank-line-after-class - D205: blank-line-after-summary - D207: under-indentation - D209: new-line-after-last-paragraph - D400: ends-in-period - D401: non-imperative-mood - D404: docstring-starts-with-this * Introducing (PL) Pylint rules sup3r doesn't conform with: - PLR2004: magic-value-comparison - PLW2901: redefined-loop-name * Running ruff with GA * Nothing is fixable for now * Using ruff with pre-commmit * style: Conforming with NPY003 & NPY201 * style: Conforming with COM819 * Forgot to include: quote-style & indent-style * Updating requirements on ruff * GA outputs ruff with github style * Adding (C4) flake8-comprehensions As suggested by @bnb32 sup3r doesn't conform with: - C408: unnecessary-collection-call - C414: unnecessary-double-cast-or-process * Adding rule (C90) mccabe As suggested by @bnb32 Using max-complexity as previously defined for flake8 (lintesrs/.flake8) as equal to 12. * Adding convention (C) and flake8-logging (LOG) @bnb32 any other rule that you would like to include? * validate all codebase with super-linter There were some misterious situations where super-linter was not properly checking the code. Paul mentioned a setup that limits checks to the very last commit only. I expect that VALIDATE_ALL_CODEBASE should address that. * Adding (SIM) flake8-simplify rules As suggested by @bnb32. sup3r doesn't conform with: - SIM108: if-else-block-instead-of-if-exp - SIM117: multiple-with-statements - SIM118: in-dict-keys - SIM211: if-expr-with-false-true * Adding (PERF) Perflint rules As suggested by @bnb32 sup3r doesn't conform with: - PERF102: incorrect-dict-iterator - PERF203: try-except-in-loop - PERF401: manual-list-comprehension * We don't need to run on the full code base anymore With the pull_request trigger we don't need VALIDATE_ALL_CODEBASE set to true anymore. Otherwise it's running twice. Thanks @ppinchuk! * clean: Removing implicit rules While conforming with the legacy setup, I added a few explicit specific rules but in the final version didn't make sense anymore since those are now implicit. For instance, no need of "E701" is added "E".
1 parent 2f53a4c commit 5dda178

File tree

10 files changed

+2446
-1836
lines changed

10 files changed

+2446
-1836
lines changed

.github/workflows/linter.yml

+12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ on:
44
push:
55
branches-ignore:
66
- 'gh-pages'
7+
pull_request:
8+
branches: [main]
79

810
jobs:
911
build:
@@ -28,3 +30,13 @@ jobs:
2830
VALIDATE_YAML: false
2931
DEFAULT_BRANCH: main
3032
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33+
ruff:
34+
name: Ruff
35+
runs-on: ubuntu-latest
36+
steps:
37+
- uses: actions/checkout@v4
38+
- uses: chartboost/ruff-action@v1
39+
with:
40+
version: 0.4.10
41+
args: check --output-format=github
42+
src: "./sup3r ./tests"

.pre-commit-config.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ repos:
1212
rev: v3.1.0
1313
hooks:
1414
- id: pylint
15+
- repo: https://github.com/astral-sh/ruff-pre-commit
16+
rev: v0.4.10
17+
hooks:
18+
- id: ruff

pixi.lock

+2,282-1,811
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+139-16
Original file line numberDiff line numberDiff line change
@@ -71,49 +71,172 @@ line-length = 79
7171
indent-width = 4
7272

7373
target-version = "py38"
74+
exclude = [
75+
"CSV",
76+
"ref.*?py",
77+
]
7478

7579
[tool.ruff.lint]
76-
fixable = ["ALL"]
77-
preview = true
80+
fixable = []
81+
# preview = true
82+
# logger-objects = []
83+
task-tags = ["TODO", "FIXME", "XXX"]
7884
select = [
85+
"A", # flake8-builtins
86+
"ARG", # flake8-unused-arguments
87+
"C",
88+
"C4", # flake8-comprehensions
89+
"C90", # mccabe
90+
"COM", # flake8-commas
91+
"D", # pydocstyle
7992
"E", # pycodestyle
8093
"F", # Pyflakes
94+
"G", # flake8-logging-format
95+
"I", # isort
96+
"LOG", # flake8-logging
97+
"N", # pep8-naming
98+
"NPY", # numpy-specific
99+
"PERF", # Perflint
100+
"PL", # Pylint
101+
"Q", # flake8-quotes
102+
"SIM", # flake8-simplify
103+
"UP", # pyupgrade
81104
"W", # Warning
82105
]
83106

84107
ignore = [
85-
"B008", # function-call-in-default-argument
86-
"B024", # abstract-base-class-without-abstract-method
87-
"B028", # no-explicit-stacklevel
88-
"B905", # zip-without-explicit-strict
108+
# Currently don't conform but we might want to reconsider
109+
"A001", # builtin-variable-shadowing
110+
# Currently don't conform but we might want to reconsider
111+
"A002", # builtin-argument-shadowing
112+
"ARG002", # unused-method-argument
113+
"ARG003", # unused-class-method-argument
114+
"ARG004", # unused-static-method-argument
115+
"ARG005", # unused-lambda-argument
116+
# "B008", # function-call-in-default-argument
117+
# "B024", # abstract-base-class-without-abstract-method
118+
# "B028", # no-explicit-stacklevel
119+
# "B905", # zip-without-explicit-strict
120+
"C408", # unnecessary-collection-call
121+
"C414", # unnecessary-double-cast-or-process
122+
"COM812", # missing-trailing-comma
89123
"D105", # undocumented-magic-method
124+
"D200", # fits-on-one-line
90125
"D202", # no-blank-line-after-function
126+
"D204", # one-blank-line-after-class
91127
"D205", # blank-line-after-summary
128+
"D207", # under-indentation
92129
"D209", # new-line-after-last-paragraph
93-
"D212", # multi-line-summary-first-line
94-
"D213", # multi-line-summary-second-linek
130+
# "D212", # multi-line-summary-first-line
131+
# "D213", # multi-line-summary-second-linek
95132
"D400", # ends-in-period
96133
"D401", # non-imperative-mood
97-
"D413", # blank-line-after-last-section
98-
"D415", # ends-in-punctuation
99-
"E902", # io-error
134+
"D404", # docstring-starts-with-this
135+
# "D413", # blank-line-after-last-section
136+
# "D415", # ends-in-punctuation
137+
# "E902", # io-error
138+
"FIX001", # line-contains-fixme
139+
# We currently don't conform but we might want to reconsider
140+
"G001", # logging-string-format
141+
# We currently don't conform but we might want to reconsider
142+
"G004", # logging-f-string
143+
"I001", # unsorted-imports
144+
"N802", # invalid-function-name
145+
"N803", # invalid-argument-name
146+
"N806", # non-lowercase-variable-in-function
147+
# Consider conforming with NPY002
148+
"NPY002", # numpy-legacy-random
149+
"PERF102", # incorrect-dict-iterator
150+
"PERF203", # try-except-in-loop
151+
"PERF401", # manual-list-comprehension
152+
"PLR0904", # too-many-public-methods
153+
"PLR0912", # too-many-branches
100154
"PLR0913", # too-many-arguments
155+
"PLR0914", # too-many-locals
156+
"PLR0915", # too-many-statements
157+
"PLR1702", # too-many-nested-blocks
158+
"PLR1704", # redefined-argument-from-local
159+
"PLR2004", # magic-value-comparison
160+
"PLW1514", # unspecified-encoding
161+
"PLW2901", # redefined-loop-name
162+
"Q000", # bad-quotes-inline-string
163+
"Q004", # unnecessary-escaped-quote
164+
"SIM108", # if-else-block-instead-of-if-exp
165+
"SIM117", #multiple-with-statements
166+
"SIM118", # in-dict-keys
167+
"SIM211", # if-expr-with-false-true
101168
"UP009", # utf8-encoding-declaration
169+
"UP015", # redundant-open-modes
102170
"UP032", # f-string
103-
"UP038" # non-pep604-isinstance
171+
# "UP038" # non-pep604-isinstance
104172
]
173+
# Ignored in pylint setup but missing on ruff. We shall delete from the
174+
# following lines what is not intended to follow anymore.
175+
# arguments-renamed
176+
# consider-using-f-string
177+
# raw-checker-failed
178+
# bad-inline-option
179+
# locally-disabled
180+
# file-ignored
181+
# suppressed-message
182+
# useless-suppression
183+
# deprecated-pragma
184+
# protected-access
185+
# redefined-outer-name
186+
# redefined-builtin
187+
# broad-except
188+
# logging-format-interpolation
189+
# logging-fstring-interpolation
190+
# wrong-import-order
191+
# wrong-import-position
192+
# relative-beyond-top-level
193+
# too-many-instance-attributes
194+
# too-few-public-methods
195+
# invalid-name
196+
# import-error
197+
# try-except-raise
198+
# no-else-raise
199+
# no-else-return
200+
# unexpected-keyword-arg
201+
# no-value-for-parameter
202+
# too-many-lines
203+
# arguments-differ
204+
# import-outside-toplevel
205+
# super-init-not-called
206+
# isinstance-second-argument-not-valid-type
207+
# inconsistent-return-statements
208+
# no-else-break
209+
# too-many-function-args
210+
# redundant-keyword-arg
211+
# c-extension-no-member
212+
213+
[tool.ruff.lint.mccabe]
214+
# Flag errors (`C901`) whenever the complexity level exceeds 5.
215+
max-complexity = 12
105216

106217
[tool.ruff.lint.per-file-ignores]
107218
"__init__.py" = [
108219
"F401", # unused-import
109220
]
110-
"docs/source/conf.py" = [
111-
"E402", # unused-import
112-
]
221+
#"docs/source/conf.py" = [
222+
# "E402", # unused-import
223+
# ]
224+
225+
[tool.ruff.lint.pylint]
226+
max-args = 5 # (PLR0913) Maximum number of arguments for function / method
227+
max-bool-expr = 5 # ( PLR0916) Boolean in a single if statement
228+
max-branches=12 # (PLR0912) branches allowed for a function or method body
229+
max-locals=15 # (PLR0912) local variables allowed for a function or method body
230+
max-nested-blocks = 5 # (PLR1702) nested blocks within a function or method body
231+
max-public-methods=20 # (R0904) public methods allowed for a class
232+
max-returns=6 # (PLR0911) return statements for a function or method body
233+
max-statements=50 # (PLR0915) statements allowed for a function or method body
113234

114235
[tool.ruff.format]
115236
quote-style = "single"
116237
indent-style = "space"
238+
# Consider adopting "lf" instead
239+
line-ending = "auto"
117240

118241
[tool.ruff.lint.pydocstyle]
119242
convention = "numpy"
@@ -167,4 +290,4 @@ pytest = ">=5.2"
167290
[tool.pixi.feature.dev.dependencies]
168291
build = ">=0.6"
169292
twine = ">=5.0"
170-
ruff = ">=0.2"
293+
ruff = ">=0.4"

sup3r/bias/mixins.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
logger = logging.getLogger(__name__)
1111

1212

13-
class FillAndSmoothMixin():
13+
class FillAndSmoothMixin:
1414
"""Fill and extend parameters for calibration on missing positions"""
1515
def fill_and_smooth(self,
1616
out,

tests/data_handling/test_data_handling_h5.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
val_split = 0.2
3030
dh_kwargs = {'target': target, 'shape': shape, 'max_delta': 20,
3131
'sample_shape': sample_shape,
32-
'lr_only_features': ('BVF*m', 'topography',),
32+
'lr_only_features': ('BVF*m', 'topography'),
3333
'temporal_slice': slice(None, None, 1),
3434
'worker_kwargs': {'max_workers': 1}}
3535
bh_kwargs = {'batch_size': 8, 'n_batches': 20,

tests/data_handling/test_data_handling_nc.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
dh_kwargs = dict(target=target,
3030
shape=shape,
3131
max_delta=20,
32-
lr_only_features=('BVF*m', 'topography',),
32+
lr_only_features=('BVF*m', 'topography'),
3333
sample_shape=sample_shape,
3434
temporal_slice=slice(None, None, 1),
3535
worker_kwargs=dict(max_workers=1),

tests/forward_pass/test_forward_pass_exo.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def test_fwp_multi_step_spatial_model_topo_noskip():
190190
max_workers = 1
191191
fwp_chunk_shape = (4, 4, 8)
192192
s_enhancements = [2, 2, 1]
193-
s_enhance = np.product(s_enhancements)
193+
s_enhance = np.prod(s_enhancements)
194194

195195
exo_kwargs = {
196196
'topography': {
@@ -299,7 +299,7 @@ def test_fwp_multi_step_model_topo_noskip():
299299
max_workers = 1
300300
fwp_chunk_shape = (4, 4, 8)
301301
s_enhancements = [2, 2, 3]
302-
s_enhance = np.product(s_enhancements)
302+
s_enhance = np.prod(s_enhancements)
303303
t_enhance = 4
304304

305305
exo_kwargs = {
@@ -955,7 +955,7 @@ def test_fwp_multi_step_model_multi_exo():
955955
max_workers = 1
956956
fwp_chunk_shape = (4, 4, 8)
957957
s_enhancements = [2, 2, 3]
958-
s_enhance = np.product(s_enhancements)
958+
s_enhance = np.prod(s_enhancements)
959959
t_enhance = 4
960960

961961
exo_kwargs = {

tests/output/test_output_handling.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def test_h5_collect_mask(log=False):
208208
(out_files, data, _, _, features, _, _, _, _, _, _) = out
209209

210210
CollectorH5.collect(out_files, fp_out, features=features)
211-
indices = np.arange(np.product(data.shape[:2]))
211+
indices = np.arange(np.prod(data.shape[:2]))
212212
indices = indices[slice(-len(indices) // 2, None)]
213213
removed = []
214214
for _ in range(10):

tests/utilities/test_utilities.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def test_weighted_box_sampler():
195195
or chunks[5][0] <= slice_3.start <= chunks[5][-1])
196196

197197
shape = (1, 1)
198-
weights = np.zeros(np.product(data.shape))
198+
weights = np.zeros(np.prod(data.shape))
199199
weights_4 = weights.copy()
200200
weights_4[5] = 1
201201

@@ -366,7 +366,7 @@ def test_t_coarsen():
366366
"""Test temporal coarsening of 5D array"""
367367
t_enhance = 4
368368
hr_shape = (3, 10, 10, 48, 2)
369-
arr = np.arange(np.product(hr_shape)).reshape(hr_shape).astype(float)
369+
arr = np.arange(np.prod(hr_shape)).reshape(hr_shape).astype(float)
370370

371371
# test 4x temporal enhancement averaging
372372
arr_lr = temporal_coarsening(arr, t_enhance=t_enhance, method='average')

0 commit comments

Comments
 (0)