Skip to content

Commit f7da23e

Browse files
committed
Replace mypy with ty, modernize ruff configuration
- Remove mypy config, use ty for type checking - Configure ruff with comprehensive lint rules (E, F, W, B, I, UP, C4, SIM, RUF) - Configure isort via ruff with plone-style settings - Fix lint issues: unused imports, mutable defaults, dict/list literals - Add ClassVar annotations for mutable class attributes
1 parent 850f8eb commit f7da23e

10 files changed

Lines changed: 98 additions & 84 deletions

File tree

CHANGES.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
- Feature: Add `qa.ty` domain for Astral's ty type checker.
88
ty is an extremely fast Python type checker (10-100x faster than mypy).
99
Registers with both CHECK_TARGETS and TYPECHECK_TARGETS for fast feedback.
10-
[jensens]
10+
[jensens, 2026-01-28]
11+
- Use ty and extended ruff for check, drop isort and mypy from `pyproject.toml`.
12+
[jensens, 2026-01-28]
1113

1214
## 2.1.0
1315

pyproject.toml

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,20 +88,34 @@ testpaths = [
8888
"src",
8989
]
9090

91-
[tool.isort]
92-
profile = "black"
93-
force_alphabetical_sort = true
94-
force_single_line = true
95-
lines_after_imports = 2
96-
97-
[tool.mypy]
98-
ignore_missing_imports = true
99-
python_version = "3.10"
100-
10191
[tool.ruff]
10292
target-version = "py310"
10393
# Exclude a variety of commonly ignored directories.
10494
exclude = ["src/mxmake/_version.py"]
10595

10696
[tool.ruff.lint]
107-
select = ["UP"] # Enable pyupgrade rules for Python 3.10+ modernization
97+
select = [
98+
"E", # pycodestyle errors
99+
"F", # pyflakes
100+
"W", # pycodestyle warnings
101+
"B", # flake8-bugbear
102+
"I", # isort
103+
"UP", # pyupgrade
104+
"C4", # flake8-comprehensions
105+
"SIM", # flake8-simplify
106+
"RUF", # ruff-specific
107+
]
108+
109+
[tool.ruff.lint.isort]
110+
force-single-line = true
111+
from-first = true
112+
lines-after-imports = 2
113+
lines-between-types = 1
114+
no-sections = true
115+
order-by-type = false
116+
117+
[tool.ruff.lint.pycodestyle]
118+
max-line-length = 120 # E501 triggers above this, allows flexibility
119+
120+
[tool.ruff.lint.per-file-ignores]
121+
"src/mxmake/tests/*" = ["E101", "RUF012"]

src/mxmake/hook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def generate_templates(self, state: mxdev.State):
3838
try:
3939
factory = template.lookup(name, bound=True)
4040
except RuntimeError as e:
41-
msg = f"mxmake: {str(e)}"
41+
msg = f"mxmake: {e!s}"
4242
logger.warning(msg)
4343
continue
4444
factory(config, environment).write()

src/mxmake/parser.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
from mxmake.topics import get_domain
22
from pathlib import Path
33

4-
import typing
5-
64

75
class SettingMissing(Exception):
86
"""Exception used in parser to indicate a missing setting in an existing

src/mxmake/templates.py

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def get_template_environment() -> Environment:
2525
class template:
2626
"""Template decorator and registry."""
2727

28-
_registry: dict = dict()
28+
_registry: typing.ClassVar[dict] = {}
2929

3030
def __init__(self, name: str) -> None:
3131
self.name = name
@@ -160,15 +160,15 @@ def template_name(self) -> str:
160160

161161
@property
162162
def template_variables(self) -> dict[str, typing.Any]:
163-
return dict(
164-
description=self.description,
165-
env=self.env,
166-
testpaths=self.package_paths(ns_name("test-path")),
167-
testargs=self.config.settings.get("mxmake-test-runner-args", ""),
168-
)
163+
return {
164+
"description": self.description,
165+
"env": self.env,
166+
"testpaths": self.package_paths(ns_name("test-path")),
167+
"testargs": self.config.settings.get("mxmake-test-runner-args", ""),
168+
}
169169

170170
def package_paths(self, attr: str) -> list[str]:
171-
paths = list()
171+
paths = []
172172
for name, package in self.config.packages.items():
173173
if attr not in package:
174174
continue
@@ -220,13 +220,13 @@ def target_folder(self) -> Path:
220220

221221
@property
222222
def template_variables(self) -> dict[str, typing.Any]:
223-
return dict(
224-
find_links=[
223+
return {
224+
"find_links": [
225225
link.strip()
226226
for link in self.settings.get("find-links", "").split("\n")
227227
if link.strip()
228228
]
229-
)
229+
}
230230

231231

232232
##############################################################################
@@ -260,17 +260,17 @@ def template_variables(self) -> dict[str, typing.Any]:
260260
for domain in self.domains:
261261
if not domain.settings:
262262
continue
263-
domain_setting = dict(fqn=domain.fqn, settings=[])
263+
domain_setting = {"fqn": domain.fqn, "settings": []}
264264
settings.append(domain_setting)
265265
for setting in domain.settings:
266266
sfqn = f"{domain.fqn}.{setting.name}"
267267
domain_setting["settings"].append(
268-
dict(
269-
name=setting.name,
270-
description=setting.description.split("\n"),
271-
default=setting.default,
272-
value=self.domain_settings.get(sfqn, setting.default),
273-
)
268+
{
269+
"name": setting.name,
270+
"description": setting.description.split("\n"),
271+
"default": setting.default,
272+
"value": self.domain_settings.get(sfqn, setting.default),
273+
}
274274
)
275275
# render domain sections
276276
sections = io.StringIO()
@@ -284,12 +284,12 @@ def template_variables(self) -> dict[str, typing.Any]:
284284
topics = {domain.topic for domain in self.domains}
285285
additional_targets["qa"] = "qa" in topics
286286
# return template variables
287-
return dict(
288-
settings=settings,
289-
sections=sections,
290-
fqns=fqns,
291-
additional_targets=additional_targets,
292-
)
287+
return {
288+
"settings": settings,
289+
"sections": sections,
290+
"fqns": fqns,
291+
"additional_targets": additional_targets,
292+
}
293293

294294

295295
##############################################################################
@@ -317,7 +317,7 @@ def target_folder(self) -> Path:
317317

318318
@property
319319
def template_variables(self) -> dict[str, typing.Any]:
320-
return dict(additional_sources_targets=self.additional_sources_targets)
320+
return {"additional_sources_targets": self.additional_sources_targets}
321321

322322

323323
##############################################################################
@@ -351,24 +351,24 @@ def template_variables(self) -> dict[str, typing.Any]:
351351
for domain in self.domains:
352352
if domain.fqn == "qa.test":
353353
mxmake_env = True
354-
template = dict(name="run-tests", settings=dict(environment="env"))
354+
template = {"name": "run-tests", "settings": {"environment": "env"}}
355355
mxmake_templates.append(template)
356356
if domain.fqn == "qa.coverage":
357357
mxmake_env = True
358-
template = dict(name="run-coverage", settings=dict(environment="env"))
358+
template = {"name": "run-coverage", "settings": {"environment": "env"}}
359359
mxmake_templates.append(template)
360360
if domain.fqn == "applications.plone":
361-
template = dict(
362-
name="plone-site",
363-
settings=dict(
364-
distribution="volto", extension_ids="plone.volto:default"
365-
),
366-
)
361+
template = {
362+
"name": "plone-site",
363+
"settings": {
364+
"distribution": "volto", "extension_ids": "plone.volto:default"
365+
},
366+
}
367367
mxmake_templates.append(template)
368-
return dict(
369-
mxmake_templates=mxmake_templates,
370-
mxmake_env=mxmake_env,
371-
)
368+
return {
369+
"mxmake_templates": mxmake_templates,
370+
"mxmake_env": mxmake_env,
371+
}
372372

373373

374374
##############################################################################
@@ -439,7 +439,7 @@ def write(self) -> None:
439439

440440

441441
class ci_template:
442-
templates: list = list()
442+
templates: typing.ClassVar[list] = []
443443

444444
def __init__(self, name: str) -> None:
445445
self.name = name
@@ -461,9 +461,9 @@ def __init__(
461461

462462
@property
463463
def template_variables(self) -> dict[str, typing.Any]:
464-
return dict(
465-
project_path_python=self.settings.get("PROJECT_PATH_PYTHON", ""),
466-
)
464+
return {
465+
"project_path_python": self.settings.get("PROJECT_PATH_PYTHON", ""),
466+
}
467467

468468
@property
469469
def target_folder(self) -> Path:
@@ -547,7 +547,7 @@ def template_variables(self):
547547
vars["distribution"] = site.pop("distribution")
548548

549549
# handle extension ids
550-
if site.get("extension_ids", None) is not None:
550+
if site.get("extension_ids") is not None:
551551
site["extension_ids"] = [
552552
eid.strip() for eid in site["extension_ids"].split("\n") if eid.strip()
553553
]
@@ -588,5 +588,5 @@ def template_variables(self):
588588
domains.append(topic.domain(domain_name.strip()))
589589
for domain in domains:
590590
for target in domain.targets:
591-
targets.append(dict(name=target.name, folder=folder))
592-
return dict(targets=targets)
591+
targets.append({"name": target.name, "folder": folder})
592+
return {"targets": targets}

src/mxmake/testing/__init__.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def wrapper(self):
2626
@contextmanager
2727
def reset_template_registry():
2828
registry_orgin = templates.template._registry
29-
templates.template._registry = dict()
29+
templates.template._registry = {}
3030
try:
3131
yield
3232
finally:
@@ -59,17 +59,17 @@ def wrapper(*a):
5959
class TestConfiguration(mxdev.Configuration):
6060
def __init__(
6161
self,
62-
settings: dict[str, str] = {},
63-
overrides: dict[str, str] = {},
64-
ignore_keys: list[str] = [],
65-
packages: dict[str, dict[str, str]] = {},
66-
hooks: dict[str, dict[str, str]] = {},
62+
settings: dict[str, str] | None = None,
63+
overrides: dict[str, str] | None = None,
64+
ignore_keys: list[str] | None = None,
65+
packages: dict[str, dict[str, str]] | None = None,
66+
hooks: dict[str, dict[str, str]] | None = None,
6767
):
68-
self.settings = settings
69-
self.overrides = overrides
70-
self.ignore_keys = ignore_keys
71-
self.packages = packages
72-
self.hooks = hooks
68+
self.settings = settings if settings is not None else {}
69+
self.overrides = overrides if overrides is not None else {}
70+
self.ignore_keys = ignore_keys if ignore_keys is not None else []
71+
self.packages = packages if packages is not None else {}
72+
self.hooks = hooks if hooks is not None else {}
7373

7474

7575
class RenderTestCase(unittest.TestCase):

src/mxmake/tests/test_templates.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import doctest
1111
import mxdev
12-
import typing
1312

1413

1514
EXPECTED_DIRECTORY = Path(__file__).parent / "expected"
@@ -23,7 +22,7 @@ def test_template(self):
2322
class Template(templates.Template):
2423
pass
2524

26-
self.assertEqual(templates.template._registry, dict(template=Template))
25+
self.assertEqual(templates.template._registry, {"template": Template})
2726
self.assertEqual(templates.template.lookup("template"), Template)
2827
with self.assertRaises(RuntimeError):
2928
templates.template.lookup("inexistent")
@@ -60,7 +59,7 @@ class Template(templates.Template):
6059
target_folder = tempdir
6160
target_name = "target.out"
6261
template_name = "target.in"
63-
template_variables = dict(param="value")
62+
template_variables = {"param": "value"}
6463

6564
# cannot write template without template environment
6665
template = Template()
@@ -99,9 +98,9 @@ class Template(templates.MxIniBoundTemplate):
9998
# template settings
10099
hooks: dict[str, dict] = {}
101100
template = Template(testing.TestConfiguration(hooks=hooks))
102-
self.assertEqual(template.settings, dict())
103-
hooks["mxmake-template"] = dict(key="val")
104-
self.assertEqual(template.settings, dict(key="val"))
101+
self.assertEqual(template.settings, {})
102+
hooks["mxmake-template"] = {"key": "val"}
103+
self.assertEqual(template.settings, {"key": "val"})
105104

106105
def test_ShellScriptTemplate(self):
107106
self.assertEqual(templates.ShellScriptTemplate.description, "")
@@ -579,11 +578,13 @@ def test_Makefile(self, tempdir):
579578

580579
template.write()
581580
print("Makefile written to", tempdir / "Makefile")
582-
with (tempdir / "Makefile").open() as result:
583-
with open(EXPECTED_DIRECTORY / "Makefile") as expected:
584-
self.checkOutput(
585-
expected.read(), result.read(), optionflags=doctest.REPORT_UDIFF
586-
)
581+
with (
582+
(tempdir / "Makefile").open() as result,
583+
(EXPECTED_DIRECTORY / "Makefile").open() as expected,
584+
):
585+
self.checkOutput(
586+
expected.read(), result.read(), optionflags=doctest.REPORT_UDIFF
587+
)
587588

588589
@testing.temp_directory
589590
def test_MxIni(self, tempdir):

src/mxmake/tests/test_topics.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from pathlib import Path
77

88
import configparser
9-
import typing
109
import unittest
1110

1211

src/mxmake/topics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def get_domain(fqn: str) -> Domain:
186186

187187
class DomainConflictError(Exception):
188188
def __init__(self, counter: Counter):
189-
conflicting = list()
189+
conflicting = []
190190
for name, count in counter.items():
191191
if count > 1:
192192
conflicting.append(name)

src/mxmake/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ def list_value(value: str | None) -> list[str]:
3131
space. Supports newline.
3232
"""
3333
if not value:
34-
return list()
34+
return []
3535
return [v.strip() for v in value.replace("\n", " ").strip().split(" ")]

0 commit comments

Comments
 (0)