Skip to content

Commit c3e83a2

Browse files
committed
dropped Python 3.9 support
and modernized the codebase to Python 3.10+
1 parent 8ac9a4c commit c3e83a2

File tree

17 files changed

+86
-87
lines changed

17 files changed

+86
-87
lines changed

.github/workflows/lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ jobs:
1818
enable-cache: true
1919
cache-dependency-glob: "pyproject.toml"
2020

21-
- name: Set up Python 3.9
22-
run: uv python install 3.9
21+
- name: Set up Python 3.10
22+
run: uv python install 3.10
2323

2424
- name: Install Project
2525
run: make install

.github/workflows/test.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ jobs:
1111
fail-fast: false
1212
matrix:
1313
python-version:
14-
- "3.9"
1514
- "3.10"
1615
- "3.11"
1716
- "3.12"
@@ -21,10 +20,6 @@ jobs:
2120
- ubuntu-latest
2221
- macos-latest
2322
- windows-latest
24-
exclude:
25-
# GH does not support macos and python 3.9
26-
- python-version: "3.9"
27-
os: macos-latest
2823
runs-on: ${{ matrix.os }}
2924
steps:
3025
- uses: actions/checkout@v5

.github/workflows/variants.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
matrix:
1313
python-version:
1414
# we test on lowest and highest supported versions
15-
- "3.9"
15+
- "3.10"
1616
- "3.14"
1717
os:
1818
- ubuntu-latest

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## 1.3.1 (unreleased)
44

5+
- **Breaking**: Drop Python 3.9 support. Minimum Python version is now 3.10.
6+
- Feature: Modernize codebase to use Python 3.10+ features (PEP 604 union types, built-in generic types).
57
- Critical fix: `SOURCES_TARGET` used mxdev wrongly with `-o` (offline) option.
68
The offline option had a bug and was fixed in mxdev [#34](https://github.com/mxstack/mxdev/issues/34) and released with mxdev>=5.
79
This fix switches from `-o` to the correct `-f` (no fetch from vcs).

docs/source/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,6 @@ Please follow [GIT's official installation instructions](https://git-scm.com/do
7373

7474
Install [make as described here](https://gist.github.com/evanwill/0207876c3243bbb6863e65ec5dc3f058#make)
7575

76-
Further you need a [Python >=3.9 installation.](https://www.python.org/downloads/windows/).
76+
Further you need a [Python >=3.10 installation.](https://www.python.org/downloads/windows/).
7777

7878
Dependent on the topics and domains you use, you may need to install additional software, but this is no different from Linux/OSX.

pyproject.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ keywords = ["development", "deployment", "make"]
66
authors = [
77
{name = "MX Stack Developers", email = "[email protected]" }
88
]
9-
requires-python = ">=3.9"
9+
requires-python = ">=3.10"
1010
license = { text = "BSD 2-Clause License" }
1111
classifiers = [
1212
"Development Status :: 5 - Production/Stable",
@@ -15,7 +15,6 @@ classifiers = [
1515
"License :: OSI Approved :: BSD License",
1616
"Operating System :: OS Independent",
1717
"Programming Language :: Python",
18-
"Programming Language :: Python :: 3.9",
1918
"Programming Language :: Python :: 3.10",
2019
"Programming Language :: Python :: 3.11",
2120
"Programming Language :: Python :: 3.12",
@@ -92,8 +91,12 @@ lines_after_imports = 2
9291

9392
[tool.mypy]
9493
ignore_missing_imports = true
95-
python_version = "3.9"
94+
python_version = "3.10"
9695

9796
[tool.ruff]
97+
target-version = "py310"
9898
# Exclude a variety of commonly ignored directories.
9999
exclude = []
100+
101+
[tool.ruff.lint]
102+
select = ["UP"] # Enable pyupgrade rules for Python 3.10+ modernization

src/mxmake/main.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def list_command(args: argparse.Namespace):
9898

9999

100100
def create_config(
101-
prompt: bool, preseeds: typing.Union[typing.Dict[str, typing.Any], None]
101+
prompt: bool, preseeds: dict[str, typing.Any] | None
102102
):
103103
if prompt and preseeds:
104104
sys.stdout.write("Either use prompt or preseeds, not both\n")
@@ -134,7 +134,7 @@ def create_config(
134134
sys.exit(1)
135135

136136
# obtain domains to include
137-
domains: typing.List[Domain] = []
137+
domains: list[Domain] = []
138138
for topic_name in topic_choice["topic"]:
139139
topic = get_topic(topic_name)
140140
all_fqns = [domain.fqn for domain in topic.domains]
@@ -154,14 +154,14 @@ def create_config(
154154
for domain_name in preseeds["topics"][topic_name]
155155
]
156156
sys.stdout.write(f"Collect domains for topic {topic_name} from preseeds.\n")
157-
domains.extend((get_domain(fqn) for fqn in selected_fqns))
157+
domains.extend(get_domain(fqn) for fqn in selected_fqns)
158158
continue
159159
if not prompt:
160160
sys.stdout.write(
161161
f"- update topic {topic_name} with domains "
162162
f"{', '.join([fqdn.split('.')[1] for fqdn in selected_fqns])}.\n"
163163
)
164-
domains.extend((get_domain(fqn) for fqn in selected_fqns))
164+
domains.extend(get_domain(fqn) for fqn in selected_fqns)
165165
continue
166166
domains_choice = inquirer.prompt(
167167
[
@@ -191,7 +191,7 @@ def create_config(
191191
settings_question = []
192192
for setting in settings:
193193
sfqn = f"{domain.fqn}.{setting.name}"
194-
setting_default: typing.Union[typing.Any, object] = setting.default
194+
setting_default: typing.Any | object = setting.default
195195
# use default setting from preseeds
196196
if preseeds:
197197
unset = object()

src/mxmake/parser.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ class SettingMissing(Exception):
1313
class MakefileParser:
1414
def __init__(self, path: Path):
1515
self.path = path
16-
self.fqns: typing.List = []
17-
self.topics: typing.Dict = {}
18-
self.settings: typing.Dict = {}
16+
self.fqns: list = []
17+
self.topics: dict = {}
18+
self.settings: dict = {}
1919
self.parse()
2020

21-
def parse_fqns(self, lines: typing.List[str]):
21+
def parse_fqns(self, lines: list[str]):
2222
for line in lines:
2323
if line.startswith("#:"):
2424
fqn = line[2:].strip()
@@ -27,7 +27,7 @@ def parse_fqns(self, lines: typing.List[str]):
2727
self.topics.setdefault(topic, [])
2828
self.topics[topic].append(name)
2929

30-
def parse_settings(self, lines: typing.List[str]):
30+
def parse_settings(self, lines: list[str]):
3131
for fqn in self.fqns:
3232
domain = get_domain(fqn)
3333
for setting in domain.settings:
@@ -37,7 +37,7 @@ def parse_settings(self, lines: typing.List[str]):
3737
except SettingMissing:
3838
continue
3939

40-
def parse_setting(self, lines: typing.List[str], name: str) -> str:
40+
def parse_setting(self, lines: list[str], name: str) -> str:
4141
setting_missing = True
4242
setting_scope = False
4343
value = ""

src/mxmake/templates.py

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

28-
_registry: typing.Dict = dict()
28+
_registry: dict = dict()
2929

3030
def __init__(self, name: str) -> None:
3131
self.name = name
3232

33-
def __call__(self, ob: typing.Type["Template"]) -> typing.Type["Template"]:
33+
def __call__(self, ob: type["Template"]) -> type["Template"]:
3434
ob.name = self.name
3535
self._registry[self.name] = ob
3636
return ob
@@ -53,7 +53,7 @@ class Template(abc.ABC):
5353

5454
def __init__(
5555
self,
56-
environment: typing.Union[Environment, None] = None,
56+
environment: Environment | None = None,
5757
) -> None:
5858
# XXX: if environment is None, default to ``get_template_environment``?
5959
self.environment = environment
@@ -71,7 +71,7 @@ def template_name(self) -> str:
7171
"""Template name to use."""
7272

7373
@abc.abstractproperty
74-
def template_variables(self) -> typing.Dict[str, typing.Any]:
74+
def template_variables(self) -> dict[str, typing.Any]:
7575
"""Variables for template rendering."""
7676

7777
def write(self) -> None:
@@ -106,13 +106,13 @@ class MxIniBoundTemplate(Template):
106106
def __init__(
107107
self,
108108
config: mxdev.Configuration,
109-
environment: typing.Union[Environment, None] = None,
109+
environment: Environment | None = None,
110110
) -> None:
111111
super().__init__(environment)
112112
self.config = config
113113

114114
@property
115-
def settings(self) -> typing.Dict[str, str]:
115+
def settings(self) -> dict[str, str]:
116116
return self.config.hooks.get(ns_name(self.name), {})
117117

118118

@@ -123,7 +123,7 @@ class ShellScriptTemplate(Template):
123123

124124
class EnvironmentTemplate(MxIniBoundTemplate):
125125
@property
126-
def env(self) -> typing.Dict[str, str]:
126+
def env(self) -> dict[str, str]:
127127
"""Dict containing environment variables."""
128128
env_name = self.settings.get("environment")
129129
return self.config.hooks.get(ns_name(env_name), {}) if env_name else {}
@@ -155,15 +155,15 @@ def template_name(self) -> str:
155155
return f"{self.test_runner}-{self.target_name}"
156156

157157
@property
158-
def template_variables(self) -> typing.Dict[str, typing.Any]:
158+
def template_variables(self) -> dict[str, typing.Any]:
159159
return dict(
160160
description=self.description,
161161
env=self.env,
162162
testpaths=self.package_paths(ns_name("test-path")),
163163
testargs=self.config.settings.get("mxmake-test-runner-args", ""),
164164
)
165165

166-
def package_paths(self, attr: str) -> typing.List[str]:
166+
def package_paths(self, attr: str) -> list[str]:
167167
paths = list()
168168
for name, package in self.config.packages.items():
169169
if attr not in package:
@@ -192,7 +192,7 @@ class CoverageScript(TestScript):
192192
description: str = "Run coverage"
193193

194194
@property
195-
def template_variables(self) -> typing.Dict[str, typing.Any]:
195+
def template_variables(self) -> dict[str, typing.Any]:
196196
variables = super().template_variables
197197
variables["sourcepaths"] = self.package_paths(ns_name("source-path"))
198198
variables["omitpaths"] = self.package_paths(ns_name("omit-path"))
@@ -215,7 +215,7 @@ def target_folder(self) -> Path:
215215
return mxmake_files()
216216

217217
@property
218-
def template_variables(self) -> typing.Dict[str, typing.Any]:
218+
def template_variables(self) -> dict[str, typing.Any]:
219219
return dict(
220220
find_links=[
221221
link.strip()
@@ -240,17 +240,17 @@ class Makefile(Template):
240240
def __init__(
241241
self,
242242
target_folder: Path,
243-
domains: typing.List[Domain],
244-
domain_settings: typing.Dict[str, str],
245-
environment: typing.Union[Environment, None] = None,
243+
domains: list[Domain],
244+
domain_settings: dict[str, str],
245+
environment: Environment | None = None,
246246
) -> None:
247247
super().__init__(environment)
248248
self.target_folder = target_folder
249249
self.domains = domains
250250
self.domain_settings = domain_settings
251251

252252
@property
253-
def template_variables(self) -> typing.Dict[str, typing.Any]:
253+
def template_variables(self) -> dict[str, typing.Any]:
254254
# collect domain settings
255255
settings = []
256256
for domain in self.domains:
@@ -301,8 +301,8 @@ class AdditionalSourcesTargets(Template):
301301

302302
def __init__(
303303
self,
304-
additional_sources_targets: typing.List[str],
305-
environment: typing.Union[Environment, None] = None,
304+
additional_sources_targets: list[str],
305+
environment: Environment | None = None,
306306
) -> None:
307307
super().__init__(environment)
308308
self.additional_sources_targets = additional_sources_targets
@@ -312,7 +312,7 @@ def target_folder(self) -> Path:
312312
return mxmake_files()
313313

314314
@property
315-
def template_variables(self) -> typing.Dict[str, typing.Any]:
315+
def template_variables(self) -> dict[str, typing.Any]:
316316
return dict(additional_sources_targets=self.additional_sources_targets)
317317

318318

@@ -331,15 +331,15 @@ class MxIni(Template):
331331
def __init__(
332332
self,
333333
target_folder: Path,
334-
domains: typing.List[Domain],
335-
environment: typing.Union[Environment, None] = None,
334+
domains: list[Domain],
335+
environment: Environment | None = None,
336336
) -> None:
337337
super().__init__(environment)
338338
self.target_folder = target_folder
339339
self.domains = domains
340340

341341
@property
342-
def template_variables(self) -> typing.Dict[str, typing.Any]:
342+
def template_variables(self) -> dict[str, typing.Any]:
343343
mxmake_templates = []
344344
mxmake_env = False
345345
for domain in self.domains:
@@ -375,7 +375,7 @@ class Topics(Template):
375375
target_folder = Path()
376376

377377
@property
378-
def template_variables(self) -> typing.Dict[str, typing.Any]:
378+
def template_variables(self) -> dict[str, typing.Any]:
379379
topics = load_topics()
380380
return {"topics": topics}
381381

@@ -404,7 +404,7 @@ class Dependencies(Template):
404404
target_folder = Path()
405405

406406
@property
407-
def template_variables(self) -> typing.Dict[str, typing.Any]:
407+
def template_variables(self) -> dict[str, typing.Any]:
408408
topics = load_topics()
409409
return {"topics": topics}
410410

@@ -426,12 +426,12 @@ def write(self) -> None:
426426

427427

428428
class ci_template:
429-
templates: typing.List = list()
429+
templates: list = list()
430430

431431
def __init__(self, name: str) -> None:
432432
self.name = name
433433

434-
def __call__(self, ob: typing.Type["Template"]) -> typing.Type["Template"]:
434+
def __call__(self, ob: type["Template"]) -> type["Template"]:
435435
template(self.name)(ob)
436436
self.templates.append(self.name)
437437
return ob

src/mxmake/templates/gh-actions-lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ jobs:
1515
enable-cache: true
1616
cache-dependency-glob: "pyproject.toml"
1717

18-
- name: Set up Python 3.9
19-
run: uv python install 3.9
18+
- name: Set up Python 3.10
19+
run: uv python install 3.10
2020

2121
- name: Install Project
2222
run: make install

0 commit comments

Comments
 (0)