Skip to content

Commit cb4c128

Browse files
Merge pull request #1273 from d-v-b/impr/modernize-pre-commit
Impr/modernize pre commit
2 parents 4893e3d + 908d226 commit cb4c128

Some content is hidden

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

67 files changed

+786
-2212
lines changed

.codespellrc

Lines changed: 0 additions & 5 deletions
This file was deleted.

.github/workflows/lint.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
extra_args: codespell --all-files
2424
- uses: pre-commit/[email protected]
2525
with:
26-
extra_args: black --all-files
26+
extra_args: ruff --all-files
2727
- uses: pre-commit/[email protected]
2828
with:
29-
extra_args: flake8 --all-files
29+
extra_args: ruff-format --all-files

.pre-commit-config.yaml

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,17 @@ repos:
2020
rev: v2.4.1
2121
hooks:
2222
- id: codespell
23-
- repo: https://github.com/pycqa/isort
24-
rev: 6.0.1 # Use the latest stable version
23+
args: [--toml, pyproject.toml]
24+
- repo: https://github.com/astral-sh/ruff-pre-commit
25+
rev: v0.8.4
2526
hooks:
26-
- id: isort
27-
args:
28-
- --profile=black # Optional, makes isort compatible with Black
29-
- repo: https://github.com/psf/black
30-
rev: 25.1.0 # matching versions in pyproject.toml and github actions
31-
hooks:
32-
- id: black
33-
args: ["-v", "src", "tests", "--diff"] # --required-version is conflicting with pre-commit
34-
- repo: https://github.com/PyCQA/flake8
35-
rev: 7.3.0
36-
hooks:
37-
# syntax tests
38-
- id: flake8
39-
args:
40-
- --select=E9,F63,F7,F82
41-
- --count
42-
- --show-source
43-
- --statistics
44-
files: src/ # a lot of files in tests are not compliant
45-
# style tests
46-
- id: flake8
47-
args:
48-
- --ignore=E203,E722,W503
49-
- --count
50-
- --max-complexity=62
51-
- --max-line-length=127
52-
- --statistics
53-
files: src/ # a lot of files in tests are not compliant
27+
# Run the linter
28+
- id: ruff
29+
args: [--fix]
30+
files: ^(src/|tests/)
31+
# Run the formatter
32+
- id: ruff-format
33+
files: ^(src/|tests/)
5434
- repo: https://github.com/rhysd/actionlint
5535
rev: v1.7.7
5636
hooks:

docs/src/api/make_pages.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@
99
nav = mkdocs_gen_files.Nav()
1010
for path in sorted(Path(package).glob("**/*.py")):
1111
with mkdocs_gen_files.open(f"api/{path.with_suffix('')}.md", "w") as f:
12-
module_path = ".".join(
13-
[p for p in path.with_suffix("").parts if p != "__init__"]
14-
)
12+
module_path = ".".join([p for p in path.with_suffix("").parts if p != "__init__"])
1513
print(f"::: {module_path}", file=f)
1614
nav[path.parts] = f"{path.with_suffix('')}.md"
1715

docs/src/tutorials/dj-top.ipynb

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,7 @@
229229
" home_city=city,\n",
230230
" home_state=state,\n",
231231
" home_zip=zipcode,\n",
232-
" date_of_birth=str(\n",
233-
" fake.date_time_between(start_date=\"-35y\", end_date=\"-15y\").date()\n",
234-
" ),\n",
232+
" date_of_birth=str(fake.date_time_between(start_date=\"-35y\", end_date=\"-15y\").date()),\n",
235233
" home_phone=fake.phone_number()[:20],\n",
236234
" )"
237235
]
@@ -261,9 +259,7 @@
261259
"\n",
262260
"StudentMajor.insert(\n",
263261
" {**s, **d, \"declare_date\": fake.date_between(start_date=datetime.date(1999, 1, 1))}\n",
264-
" for s, d in zip(\n",
265-
" Student.fetch(\"KEY\"), random.choices(Department.fetch(\"KEY\"), k=len(Student()))\n",
266-
" )\n",
262+
" for s, d in zip(Student.fetch(\"KEY\"), random.choices(Department.fetch(\"KEY\"), k=len(Student())))\n",
267263
" if random.random() < 0.75\n",
268264
")\n",
269265
"\n",
@@ -318,17 +314,11 @@
318314
" ]\n",
319315
")\n",
320316
"\n",
321-
"Term.insert(\n",
322-
" dict(term_year=year, term=term)\n",
323-
" for year in range(1999, 2019)\n",
324-
" for term in [\"Spring\", \"Summer\", \"Fall\"]\n",
325-
")\n",
317+
"Term.insert(dict(term_year=year, term=term) for year in range(1999, 2019) for term in [\"Spring\", \"Summer\", \"Fall\"])\n",
326318
"\n",
327319
"Term().fetch(order_by=(\"term_year DESC\", \"term DESC\"), as_dict=True, limit=1)[0]\n",
328320
"\n",
329-
"CurrentTerm().insert1(\n",
330-
" {**Term().fetch(order_by=(\"term_year DESC\", \"term DESC\"), as_dict=True, limit=1)[0]}\n",
331-
")\n",
321+
"CurrentTerm().insert1({**Term().fetch(order_by=(\"term_year DESC\", \"term DESC\"), as_dict=True, limit=1)[0]})\n",
332322
"\n",
333323
"\n",
334324
"def make_section(prob):\n",
@@ -372,10 +362,7 @@
372362
" sections = ((Section & term) - (Course & (Enroll & student))).fetch(\"KEY\")\n",
373363
" if sections:\n",
374364
" Enroll.insert(\n",
375-
" {**student, **section}\n",
376-
" for section in random.sample(\n",
377-
" sections, random.randrange(min(5, len(sections)))\n",
378-
" )\n",
365+
" {**student, **section} for section in random.sample(sections, random.randrange(min(5, len(sections))))\n",
379366
" )\n",
380367
"\n",
381368
"# assign random grades\n",
@@ -385,10 +372,7 @@
385372
"random.shuffle(grade_keys)\n",
386373
"grade_keys = grade_keys[: len(grade_keys) * 9 // 10]\n",
387374
"\n",
388-
"Grade.insert(\n",
389-
" {**key, \"grade\": grade}\n",
390-
" for key, grade in zip(grade_keys, random.choices(grades, k=len(grade_keys)))\n",
391-
")"
375+
"Grade.insert({**key, \"grade\": grade} for key, grade in zip(grade_keys, random.choices(grades, k=len(grade_keys))))"
392376
]
393377
},
394378
{
@@ -544,9 +528,7 @@
544528
}
545529
],
546530
"source": [
547-
"(Grade * LetterGrade) & \"term_year='2018'\" & dj.Top(\n",
548-
" limit=5, order_by=\"points DESC\", offset=5\n",
549-
")"
531+
"(Grade * LetterGrade) & \"term_year='2018'\" & dj.Top(limit=5, order_by=\"points DESC\", offset=5)"
550532
]
551533
},
552534
{
@@ -566,11 +548,7 @@
566548
}
567549
],
568550
"source": [
569-
"(\n",
570-
" (LetterGrade * Grade)\n",
571-
" & \"term_year='2018'\"\n",
572-
" & dj.Top(limit=10, order_by=\"points DESC\", offset=0)\n",
573-
").make_sql()"
551+
"((LetterGrade * Grade) & \"term_year='2018'\" & dj.Top(limit=10, order_by=\"points DESC\", offset=0)).make_sql()"
574552
]
575553
},
576554
{
@@ -590,11 +568,7 @@
590568
}
591569
],
592570
"source": [
593-
"(\n",
594-
" (Grade * LetterGrade)\n",
595-
" & \"term_year='2018'\"\n",
596-
" & dj.Top(limit=20, order_by=\"points DESC\", offset=0)\n",
597-
").make_sql()"
571+
"((Grade * LetterGrade) & \"term_year='2018'\" & dj.Top(limit=20, order_by=\"points DESC\", offset=0)).make_sql()"
598572
]
599573
},
600574
{
@@ -800,9 +774,7 @@
800774
}
801775
],
802776
"source": [
803-
"(Grade * LetterGrade) & \"term_year='2018'\" & dj.Top(\n",
804-
" limit=20, order_by=\"points DESC\", offset=0\n",
805-
")"
777+
"(Grade * LetterGrade) & \"term_year='2018'\" & dj.Top(limit=20, order_by=\"points DESC\", offset=0)"
806778
]
807779
},
808780
{
@@ -1008,9 +980,7 @@
1008980
}
1009981
],
1010982
"source": [
1011-
"(LetterGrade * Grade) & \"term_year='2018'\" & dj.Top(\n",
1012-
" limit=20, order_by=\"points DESC\", offset=0\n",
1013-
")"
983+
"(LetterGrade * Grade) & \"term_year='2018'\" & dj.Top(limit=20, order_by=\"points DESC\", offset=0)"
1014984
]
1015985
},
1016986
{

pyproject.toml

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,47 @@ test = [
9191
[project.optional-dependencies]
9292
dev = [
9393
"pre-commit",
94-
"black==24.2.0",
95-
"flake8",
96-
"isort",
94+
"ruff",
9795
"codespell",
9896
# including test
9997
"pytest",
10098
"pytest-cov",
10199
]
102100

103-
[tool.isort]
104-
profile = "black"
101+
[tool.ruff]
102+
# Equivalent to flake8 configuration
103+
line-length = 127
104+
target-version = "py39"
105+
106+
[tool.ruff.lint]
107+
# Enable specific rule sets equivalent to flake8 configuration
108+
select = [
109+
"E", # pycodestyle errors
110+
"W", # pycodestyle warnings
111+
"F", # pyflakes
112+
"C90", # mccabe complexity
113+
]
114+
115+
# Ignore specific rules (equivalent to flake8 --ignore)
116+
ignore = [
117+
"E203", # whitespace before ':'
118+
"E722", # bare except
119+
]
120+
121+
# Per-file ignores (equivalent to flake8 --per-file-ignores)
122+
[tool.ruff.lint.per-file-ignores]
123+
"datajoint/diagram.py" = ["C901"] # function too complex
124+
"tests/test_blob_matlab.py" = ["E501"] # SQL hex strings cannot be broken across lines
125+
126+
[tool.ruff.lint.mccabe]
127+
# Maximum complexity (equivalent to flake8 --max-complexity)
128+
max-complexity = 62
129+
130+
[tool.ruff.format]
131+
# Use black-compatible formatting
132+
quote-style = "double"
133+
indent-style = "space"
134+
line-ending = "auto"
105135

106136
[tool.setuptools]
107137
packages = ["datajoint"]
@@ -110,6 +140,13 @@ package-dir = {"" = "src"}
110140
[tool.setuptools.dynamic]
111141
version = { attr = "datajoint.version.__version__"}
112142

143+
[tool.codespell]
144+
skip = ".git,*.pdf,*.svg,*.csv,*.ipynb,*.drawio"
145+
# Rever -- nobody knows
146+
# numer -- numerator variable
147+
# astroid -- Python library name (not "asteroid")
148+
ignore-words-list = "rever,numer,astroid"
149+
113150
[tool.pytest_env]
114151
# Default values - pytest fixtures will override with actual container details
115152
DJ_USER="root"

src/datajoint/admin.py

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,14 @@ def set_password(new_password=None, connection=None, update_config=None):
2020
logger.warning("Failed to confirm the password! Aborting password change.")
2121
return
2222

23-
if version.parse(
24-
connection.query("select @@version;").fetchone()[0]
25-
) >= version.parse("5.7"):
23+
if version.parse(connection.query("select @@version;").fetchone()[0]) >= version.parse("5.7"):
2624
# SET PASSWORD is deprecated as of MySQL 5.7 and removed in 8+
2725
connection.query("ALTER USER user() IDENTIFIED BY '%s';" % new_password)
2826
else:
2927
connection.query("SET PASSWORD = PASSWORD('%s')" % new_password)
3028
logger.info("Password updated.")
3129

32-
if update_config or (
33-
update_config is None and user_choice("Update local setting?") == "yes"
34-
):
30+
if update_config or (update_config is None and user_choice("Update local setting?") == "yes"):
3531
config["database.password"] = new_password
3632
config.save_local(verbose=True)
3733

@@ -67,17 +63,10 @@ def kill(restriction=None, connection=None, order_by=None):
6763
while True:
6864
print(" ID USER HOST STATE TIME INFO")
6965
print("+--+ +----------+ +-----------+ +-----------+ +-----+")
70-
cur = (
71-
{k.lower(): v for k, v in elem.items()}
72-
for elem in connection.query(query, as_dict=True)
73-
)
66+
cur = ({k.lower(): v for k, v in elem.items()} for elem in connection.query(query, as_dict=True))
7467
for process in cur:
7568
try:
76-
print(
77-
"{id:>4d} {user:<12s} {host:<12s} {state:<12s} {time:>7d} {info}".format(
78-
**process
79-
)
80-
)
69+
print("{id:>4d} {user:<12s} {host:<12s} {state:<12s} {time:>7d} {info}".format(**process))
8170
except TypeError:
8271
print(process)
8372
response = input('process to kill or "q" to quit > ')
@@ -111,15 +100,11 @@ def kill_quick(restriction=None, connection=None):
111100
if connection is None:
112101
connection = conn()
113102

114-
query = (
115-
"SELECT * FROM information_schema.processlist WHERE id <> CONNECTION_ID()"
116-
+ ("" if restriction is None else " AND (%s)" % restriction)
103+
query = "SELECT * FROM information_schema.processlist WHERE id <> CONNECTION_ID()" + (
104+
"" if restriction is None else " AND (%s)" % restriction
117105
)
118106

119-
cur = (
120-
{k.lower(): v for k, v in elem.items()}
121-
for elem in connection.query(query, as_dict=True)
122-
)
107+
cur = ({k.lower(): v for k, v in elem.items()} for elem in connection.query(query, as_dict=True))
123108
nkill = 0
124109
for process in cur:
125110
connection.query("kill %d" % process["id"])

src/datajoint/attribute_adapter.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,14 @@ def get_adapter(context, adapter_name):
4545
try:
4646
adapter = context[adapter_name]
4747
except KeyError:
48-
raise DataJointError(
49-
"Attribute adapter '{adapter_name}' is not defined.".format(
50-
adapter_name=adapter_name
51-
)
52-
)
48+
raise DataJointError("Attribute adapter '{adapter_name}' is not defined.".format(adapter_name=adapter_name))
5349
if not isinstance(adapter, AttributeAdapter):
5450
raise DataJointError(
5551
"Attribute adapter '{adapter_name}' must be an instance of datajoint.AttributeAdapter".format(
5652
adapter_name=adapter_name
5753
)
5854
)
59-
if not isinstance(adapter.attribute_type, str) or not re.match(
60-
r"^\w", adapter.attribute_type
61-
):
55+
if not isinstance(adapter.attribute_type, str) or not re.match(r"^\w", adapter.attribute_type):
6256
raise DataJointError(
6357
"Invalid attribute type {type} in attribute adapter '{adapter_name}'".format(
6458
type=adapter.attribute_type, adapter_name=adapter_name

0 commit comments

Comments
 (0)