Skip to content

Commit ee10bcc

Browse files
authored
Adopt ruff and address lint (#809)
* adopt ruff and address lint * lint
1 parent 898a1bf commit ee10bcc

19 files changed

Lines changed: 235 additions & 203 deletions

.github/dependabot.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
version: 2
22
updates:
3-
# Set update schedule for GitHub Actions
43
- package-ecosystem: "github-actions"
54
directory: "/"
65
schedule:
7-
# Check for updates to GitHub Actions every weekday
6+
interval: "weekly"
7+
- package-ecosystem: "pip"
8+
directory: "/"
9+
schedule:
810
interval: "weekly"

.github/workflows/tests.yml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ jobs:
5757
run: |
5858
hatch run test:nowarn || hatch run test:nowarn --lf
5959
60+
test_lint:
61+
name: Test Lint
62+
runs-on: ubuntu-latest
63+
steps:
64+
- uses: actions/checkout@v3
65+
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
66+
- name: Run Linters
67+
run: |
68+
hatch run typing:test
69+
hatch run lint:style
70+
pipx run 'validate-pyproject[all]' pyproject.toml
71+
pipx run doc8 --max-line-length=200
72+
6073
test_docs:
6174
timeout-minutes: 10
6275
runs-on: ubuntu-latest
@@ -121,19 +134,11 @@ jobs:
121134
with:
122135
token: ${{ secrets.GITHUB_TOKEN }}
123136

124-
pre_commit:
125-
name: pre-commit
126-
runs-on: ubuntu-latest
127-
steps:
128-
- uses: actions/checkout@v3
129-
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
130-
- uses: jupyterlab/maintainer-tools/.github/actions/pre-commit@v1
131-
132137
tests_check: # This job does nothing and is only used for the branch protection
133138
if: always()
134139
needs:
135140
- tests
136-
- pre_commit
141+
- test_lint
137142
- test_docs
138143
- test_minimum_versions
139144
- test_prereleases

.pre-commit-config.yaml

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,40 @@
1+
ci:
2+
autoupdate_schedule: monthly
3+
14
repos:
25
- repo: https://github.com/pre-commit/pre-commit-hooks
36
rev: v4.4.0
47
hooks:
5-
- id: debug-statements
6-
stages: [manual]
8+
- id: end-of-file-fixer
9+
- id: check-case-conflict
10+
- id: check-executables-have-shebangs
11+
- id: requirements-txt-fixer
712
- id: check-added-large-files
8-
stages: [manual]
913
- id: check-case-conflict
10-
stages: [manual]
1114
- id: check-toml
12-
stages: [manual]
1315
- id: check-yaml
14-
stages: [manual]
16+
- id: debug-statements
1517
- id: forbid-new-submodules
16-
stages: [manual]
1718
- id: check-builtin-literals
18-
stages: [manual]
19-
- id: check-case-conflict
20-
stages: [manual]
21-
- id: check-executables-have-shebangs
22-
stages: [manual]
23-
- id: end-of-file-fixer
24-
- id: requirements-txt-fixer
2519
- id: trailing-whitespace
2620

27-
- repo: https://github.com/psf/black
28-
rev: 22.10.0
29-
hooks:
30-
- id: black
31-
args: ["--line-length", "100"]
32-
33-
- repo: https://github.com/PyCQA/isort
34-
rev: 5.10.1
35-
hooks:
36-
- id: isort
37-
files: \.py$
38-
args: [--profile=black]
39-
40-
- repo: https://github.com/pre-commit/mirrors-mypy
41-
rev: v0.991
42-
hooks:
43-
- id: mypy
44-
args: ["--config-file", "pyproject.toml"]
45-
exclude: "traitlets/.*tests/.*.py"
46-
additional_dependencies: [pytest, types-docutils, sphinx]
47-
stages: [manual]
48-
49-
- repo: https://github.com/abravalheri/validate-pyproject
50-
rev: v0.10.1
21+
- repo: https://github.com/python-jsonschema/check-jsonschema
22+
rev: 0.19.2
5123
hooks:
52-
- id: validate-pyproject
53-
stages: [manual]
24+
- id: check-github-workflows
5425

5526
- repo: https://github.com/executablebooks/mdformat
5627
rev: 0.7.16
5728
hooks:
5829
- id: mdformat
5930

60-
- repo: https://github.com/asottile/pyupgrade
61-
rev: v3.3.0
62-
hooks:
63-
- id: pyupgrade
64-
args: [--py37-plus]
65-
66-
- repo: https://github.com/PyCQA/doc8
67-
rev: v1.0.0
68-
hooks:
69-
- id: doc8
70-
args: [--max-line-length=200]
71-
stages: [manual]
72-
73-
- repo: https://github.com/john-hen/Flake8-pyproject
74-
rev: 1.2.2
31+
- repo: https://github.com/psf/black
32+
rev: 22.10.0
7533
hooks:
76-
- id: Flake8-pyproject
77-
alias: flake8
78-
additional_dependencies:
79-
["flake8-bugbear==22.6.22", "flake8-implicit-str-concat==0.2.0"]
80-
stages: [manual]
34+
- id: black
8135

82-
- repo: https://github.com/python-jsonschema/check-jsonschema
83-
rev: 0.19.2
36+
- repo: https://github.com/charliermarsh/ruff-pre-commit
37+
rev: v0.0.165
8438
hooks:
85-
- id: check-github-workflows
39+
- id: ruff
40+
args: ["--fix"]

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
# We load the ipython release info into a dict by explicit execution
3131
_release = {} # type:ignore
32-
exec(
32+
exec( # noqa
3333
compile(
3434
open(osp.join(ROOT, "traitlets/_version.py")).read(),
3535
"../../traitlets/_version.py",

docs/sphinxext/github.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from docutils import nodes, utils
2121
from docutils.parsers.rst.roles import set_classes
22-
from sphinx.util.logging import getLogger
22+
from sphinx.util.logging import getLogger # type:ignore
2323

2424
info = getLogger(__name__).info
2525

@@ -41,7 +41,9 @@ def make_link_node(rawtext, app, type, slug, options):
4141
if not base.endswith("/"):
4242
base += "/"
4343
except AttributeError as err:
44-
raise ValueError("github_project_url configuration value is not set (%s)" % str(err))
44+
raise ValueError(
45+
"github_project_url configuration value is not set (%s)" % str(err)
46+
) from err
4547

4648
ref = base + type + "/" + slug + "/"
4749
set_classes(options)
@@ -147,7 +149,9 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options=None, content=No
147149
if not base.endswith("/"):
148150
base += "/"
149151
except AttributeError as err:
150-
raise ValueError("github_project_url configuration value is not set (%s)" % str(err))
152+
raise ValueError(
153+
"github_project_url configuration value is not set (%s)" % str(err)
154+
) from err
151155

152156
ref = base + text
153157
node = nodes.reference(rawtext, text[:6], refuri=ref, **options)

pyproject.toml

Lines changed: 85 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ docs = [
2828
"pydata-sphinx-theme",
2929
"sphinx"
3030
]
31+
lint = ["black>=22.6.0", "mdformat>0.7", "ruff>=0.0.156"]
32+
typing = ["mypy>=0.990"]
3133

3234
[tool.hatch.version]
3335
path = "traitlets/_version.py"
@@ -50,6 +52,26 @@ dependencies = ["coverage", "pytest-cov"]
5052
test = "python -m pytest -vv --cov traitlets --cov-branch --cov-report term-missing:skip-covered {args}"
5153
nowarn = "test -W default {args}"
5254

55+
[tool.hatch.envs.typing]
56+
features = ["test", "typing"]
57+
dependencies = ["mypy>=0.990"]
58+
[tool.hatch.envs.typing.scripts]
59+
test = "mypy --install-types --non-interactive {args:.}"
60+
61+
[tool.hatch.envs.lint]
62+
features = ["lint"]
63+
[tool.hatch.envs.lint.scripts]
64+
style = [
65+
"ruff {args:.}",
66+
"black --check --diff {args:.}",
67+
"mdformat --check {args:docs *.md}"
68+
]
69+
fmt = [
70+
"black {args:.}",
71+
"ruff --fix {args:.}",
72+
"mdformat {args:docs *.md}"
73+
]
74+
5375
[tool.mypy]
5476
check_untyped_defs = true
5577
disallow_any_generics = true
@@ -115,27 +137,69 @@ exclude_lines = [
115137
"@(abc\\.)?abstractmethod",
116138
]
117139

118-
[tool.flake8]
119-
ignore = "E501, W503, E402"
120-
builtins = "c, get_config"
121-
exclude = [
122-
".cache",
123-
".github",
124-
"docs",
125-
"setup.py",
140+
[tool.black]
141+
line-length = 100
142+
skip-string-normalization = true
143+
target-version = ["py37"]
144+
145+
[tool.ruff]
146+
target-version = "py37"
147+
line-length = 100
148+
select = [
149+
"A", "B", "C", "E", "F", "FBT", "I", "N", "Q", "RUF", "S", "T",
150+
"UP", "W", "YTT",
126151
]
127-
enable-extensions = "G"
128-
extend-ignore = [
129-
"G001", "G002", "G004", "G200", "G201", "G202",
130-
# black adds spaces around ':'
131-
"E203",
152+
ignore = [
153+
# Allow non-abstract empty methods in abstract base classes
154+
"B027",
155+
# Ignore McCabe complexity
156+
"C901",
157+
# Allow boolean positional values in function calls, like `dict.get(... True)`
158+
"FBT003",
159+
# Use of `assert` detected
160+
"S101",
161+
# Line too long
162+
"E501",
163+
# Relative imports are banned
164+
"I252",
165+
# Boolean ... in function definition
166+
"FBT001", "FBT002",
167+
# Module level import not at top of file
168+
"E402",
169+
# A001/A002/A003 .. is shadowing a python builtin
170+
"A001", "A002", "A003",
171+
# Possible hardcoded password
172+
"S105", "S106",
173+
# Q000 Single quotes found but double quotes preferred
174+
"Q000",
175+
# N806 Variable `B` in function should be lowercase
176+
"N806",
177+
# T201 `print` found
178+
"T201",
179+
# N802 Function name `CreateWellKnownSid` should be lowercase
180+
"N802", "N803",
181+
# C408 Unnecessary `dict` call (rewrite as a literal)
182+
"C408",
183+
# N801 Class name `directional_link` should use CapWords convention
184+
"N801",
132185
]
133-
per-file-ignores = [
134-
# B011: Do not call assert False since python -O removes these calls
135-
# F841 local variable 'foo' is assigned to but never used
136-
"traitlets/tests/*: B011", "F841",
137-
# F401 'foo' imported but unused
138-
# F403 'from foo import *' used; unable to detect undefined names
139-
"traitlets/__init__.py: F401", "F403",
140-
"traitlets/*/__init__.py: F401", "F403",
186+
unfixable = [
187+
# Don't touch print statements
188+
"T201",
189+
# Don't touch noqa lines
190+
"RUF100",
141191
]
192+
193+
[tool.ruff.per-file-ignores]
194+
# B011 Do not call assert False since python -O removes these calls
195+
# F841 local variable 'foo' is assigned to but never used
196+
# C408 Unnecessary `dict` call
197+
# E402 Module level import not at top of file
198+
# T201 `print` found
199+
# B007 Loop control variable `i` not used within the loop body.
200+
# N802 Function name `assertIn` should be lowercase
201+
# F841 Local variable `t` is assigned to but never used
202+
"traitlets/tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802", "F841"]
203+
# F401 `_version.__version__` imported but unused
204+
# F403 `from .traitlets import *` used; unable to detect undefined names
205+
"traitlets/*__init__.py" = ["F401", "F403"]

traitlets/config/application.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,9 @@ def _log_default(self):
366366
# flags are loaded from this dict by '--key' flags
367367
# this must be a dict of two-tuples, the first element being the Config/dict
368368
# and the second being the help string for the flag
369-
flags: t.Dict[t.Union[str, t.Tuple[str, ...]], t.Tuple[t.Union[t.Dict, Config], str]] = {
369+
flags: t.Dict[
370+
t.Union[str, t.Tuple[str, ...]], t.Tuple[t.Union[t.Dict[str, t.Any], Config], str]
371+
] = {
370372
"debug": (
371373
{
372374
"Application": {
@@ -537,12 +539,13 @@ def emit_alias_help(self):
537539
fhelp = cls.class_get_trait_help(trait, helptext=fhelp).splitlines()
538540

539541
if not isinstance(alias, tuple):
540-
alias = (alias,) # type:ignore[assignment]
542+
alias = (alias,)
541543
alias = sorted(alias, key=len) # type:ignore[assignment]
542544
alias = ", ".join(("--%s" if len(m) > 1 else "-%s") % m for m in alias)
543545

544546
# reformat first line
545-
fhelp[0] = fhelp[0].replace("--" + longname, alias)
547+
assert fhelp is not None
548+
fhelp[0] = fhelp[0].replace("--" + longname, alias) # type:ignore
546549
yield from fhelp
547550
yield indent("Equivalent to: [--%s]" % longname)
548551
except Exception as ex:
@@ -561,7 +564,7 @@ def emit_flag_help(self):
561564
for flags, (cfg, fhelp) in self.flags.items():
562565
try:
563566
if not isinstance(flags, tuple):
564-
flags = (flags,) # type:ignore[assignment]
567+
flags = (flags,)
565568
flags = sorted(flags, key=len) # type:ignore[assignment]
566569
flags = ", ".join(("--%s" if len(m) > 1 else "-%s") % m for m in flags)
567570
yield flags
@@ -748,7 +751,7 @@ def flatten_flags(self):
748751
for alias, longname in self.aliases.items():
749752
if isinstance(longname, tuple):
750753
longname, _ = longname
751-
cls, trait = longname.split(".", 1)
754+
cls, trait = longname.split(".", 1) # type:ignore
752755
children = mro_tree[cls] # type:ignore[index]
753756
if len(children) == 1:
754757
# exactly one descendent, promote alias
@@ -763,7 +766,7 @@ def flatten_flags(self):
763766
flags = {}
764767
for key, (flagdict, help) in self.flags.items():
765768
newflag: t.Dict[t.Any, t.Any] = {}
766-
for cls, subdict in flagdict.items():
769+
for cls, subdict in flagdict.items(): # type:ignore
767770
children = mro_tree[cls] # type:ignore[index]
768771
# exactly one descendent, promote flag section
769772
if len(children) == 1:
@@ -775,7 +778,7 @@ def flatten_flags(self):
775778
newflag[cls] = subdict
776779

777780
if not isinstance(key, tuple):
778-
key = (key,) # type:ignore[assignment]
781+
key = (key,)
779782
for k in key:
780783
flags[k] = (newflag, help)
781784
return flags, aliases
@@ -952,7 +955,7 @@ def generate_config_file(self, classes=None):
952955
"""generate default config file from Configurables"""
953956
lines = ["# Configuration file for %s." % self.name]
954957
lines.append("")
955-
lines.append("c = get_config() # noqa")
958+
lines.append("c = get_config() #" + "noqa")
956959
lines.append("")
957960
classes = self.classes if classes is None else classes
958961
config_classes = list(self._classes_with_config_traits(classes))

0 commit comments

Comments
 (0)