Skip to content

Commit e6c086b

Browse files
authored
Merge pull request #63 from mxstack/feature/drop-python-38-39-support
Drop Python 3.8/3.9 support, bump to version 5.0.0
2 parents a785cf1 + 3ad8c24 commit e6c086b

24 files changed

+264
-261
lines changed

.github/workflows/tests.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ jobs:
2727
- windows-latest
2828
- macos-latest
2929
python-config:
30-
- version: "3.8"
31-
tox-env: "py38"
32-
- version: "3.9"
33-
tox-env: "py39"
3430
- version: "3.10"
3531
tox-env: "py310"
3632
- version: "3.11"

CHANGES.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
## Changes
22

3+
## 5.0.0 (unreleased)
4+
5+
**Breaking Changes:**
6+
- Drop support for Python 3.8 and 3.9. Minimum required version is now Python 3.10.
7+
[jensens]
8+
9+
**Code Modernization:**
10+
- Modernize type hints to use Python 3.10+ syntax (PEP 604: `X | Y` instead of `Union[X, Y]`)
11+
- Use built-in generic types (`list`, `dict`, `tuple`) instead of `typing.List`, `typing.Dict`, `typing.Tuple`
12+
[jensens]
13+
314
## 4.1.2 (unreleased)
415

516
- Fix #54: Add `fixed` install mode for non-editable installations to support production and Docker deployments. The new `editable` mode replaces `direct` as the default (same behavior, clearer naming). The `direct` mode is now deprecated but still works with a warning. Install modes: `editable` (with `-e`, for development), `fixed` (without `-e`, for production/Docker), `skip` (clone only).

CLAUDE.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ make coverage-html # Run tests + combine + open HTML report
7777
Coverage is automatically collected and combined from all matrix test runs in GitHub Actions:
7878

7979
**Process:**
80-
1. Each test job (Python 3.8-3.14, Ubuntu/Windows/macOS) uploads its `.coverage.*` file as an artifact
80+
1. Each test job (Python 3.10-3.14, Ubuntu/Windows/macOS) uploads its `.coverage.*` file as an artifact
8181
2. A dedicated `coverage` job downloads all artifacts
8282
3. Coverage is combined using `coverage combine`
8383
4. Reports are generated:
@@ -129,7 +129,7 @@ isort src/mxdev
129129

130130
### Testing Multiple Python Versions (using uvx tox with uv)
131131
```bash
132-
# Run tests on all supported Python versions (Python 3.8-3.14)
132+
# Run tests on all supported Python versions (Python 3.10-3.14)
133133
# This uses uvx to run tox with tox-uv plugin for much faster testing (10-100x speedup)
134134
uvx --with tox-uv tox
135135

@@ -254,7 +254,7 @@ The codebase follows a three-phase pipeline:
254254
1. **Minimal dependencies**: Only `packaging` at runtime - no requests, no YAML parsers
255255
2. **Standard library first**: Uses `configparser`, `urllib`, `threading` instead of third-party libs
256256
3. **No pip invocation**: mxdev generates files; users run pip separately
257-
4. **Backward compatibility**: Supports Python 3.8+ with version detection for Git commands
257+
4. **Backward compatibility**: Supports Python 3.10+ with version detection for Git commands
258258

259259
## Configuration System
260260

@@ -403,7 +403,7 @@ myext-package_setting = value
403403

404404
- **Formatting**: Black-compatible (max line length: 120)
405405
- **Import sorting**: isort with `force_alphabetical_sort = true`, `force_single_line = true`
406-
- **Type hints**: Use throughout (Python 3.8+ compatible)
406+
- **Type hints**: Use throughout (Python 3.10+ compatible)
407407
- **Path handling**: Prefer `pathlib.Path` over `os.path` for path operations
408408
- Use `pathlib.Path().as_posix()` for cross-platform path comparison
409409
- Use `/` operator for path joining: `Path("dir") / "file.txt"`
@@ -424,9 +424,9 @@ The project uses GitHub Actions for continuous integration, configured in [.gith
424424

425425
**Test Job:**
426426
- **Matrix testing** across:
427-
- Python versions: 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
427+
- Python versions: 3.10, 3.11, 3.12, 3.13, 3.14
428428
- Operating systems: Ubuntu, Windows, macOS
429-
- Total: 21 combinations (7 Python × 3 OS)
429+
- Total: 15 combinations (5 Python × 3 OS)
430430
- Uses: `uvx --with tox-uv tox -e py{version}`
431431
- Leverages `astral-sh/setup-uv@v7` action for uv installation
432432

@@ -674,7 +674,7 @@ gh pr checks <PR_NUMBER>
674674

675675
## Requirements
676676

677-
- **Python**: 3.8+
677+
- **Python**: 3.10+
678678
- **pip**: 23+ (required for proper operation)
679679
- **Runtime dependencies**: Only `packaging`
680680
- **VCS tools**: Install git, svn, hg, bzr, darcs as needed for VCS operations

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ PRIMARY_PYTHON?=3.14
5151

5252
# Minimum required Python version.
5353
# Default: 3.9
54-
PYTHON_MIN_VERSION?=3.7
54+
PYTHON_MIN_VERSION?=3.10
5555

5656
# Install packages using the given package installer method.
5757
# Supported are `pip` and `uv`. If uv is used, its global availability is

pyproject.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ keywords = ["pip", "vcs", "git", "development"]
66
authors = [
77
{name = "MX Stack Developers", email = "dev@bluedynamics.com" }
88
]
9-
requires-python = ">=3.8"
9+
requires-python = ">=3.10"
1010
license = { text = "BSD 2-Clause License" }
1111
classifiers = [
1212
"Development Status :: 5 - Production/Stable",
@@ -15,8 +15,6 @@ classifiers = [
1515
"License :: OSI Approved :: BSD License",
1616
"Operating System :: OS Independent",
1717
"Programming Language :: Python",
18-
"Programming Language :: Python :: 3.8",
19-
"Programming Language :: Python :: 3.9",
2018
"Programming Language :: Python :: 3.10",
2119
"Programming Language :: Python :: 3.11",
2220
"Programming Language :: Python :: 3.12",
@@ -173,7 +171,7 @@ directory = "htmlcov"
173171

174172
[tool.tox]
175173
requires = ["tox>=4", "tox-uv>=1"]
176-
env_list = ["lint", "py38", "py39", "py310", "py311", "py312", "py313", "py314"]
174+
env_list = ["lint", "py310", "py311", "py312", "py313", "py314"]
177175

178176
[tool.tox.env_run_base]
179177
description = "Run tests with pytest and coverage"

src/mxdev/config.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ def to_bool(value):
1717

1818

1919
class Configuration:
20-
settings: typing.Dict[str, str]
21-
overrides: typing.Dict[str, str]
22-
ignore_keys: typing.List[str]
23-
packages: typing.Dict[str, typing.Dict[str, str]]
24-
hooks: typing.Dict[str, typing.Dict[str, str]]
20+
settings: dict[str, str]
21+
overrides: dict[str, str]
22+
ignore_keys: list[str]
23+
packages: dict[str, dict[str, str]]
24+
hooks: dict[str, dict[str, str]]
2525

2626
def __init__(
2727
self,
2828
mxini: str,
29-
override_args: typing.Dict = {},
30-
hooks: typing.List["Hook"] = [],
29+
override_args: dict = {},
30+
hooks: list["Hook"] = [],
3131
) -> None:
3232
logger.debug("Read configuration")
3333
data = read_with_included(mxini)
@@ -164,9 +164,9 @@ def out_constraints(self) -> str:
164164
return self.settings.get("constraints-out", "constraints-mxdev.txt")
165165

166166
@property
167-
def package_keys(self) -> typing.List[str]:
167+
def package_keys(self) -> list[str]:
168168
return [k.lower() for k in self.packages]
169169

170170
@property
171-
def override_keys(self) -> typing.List[str]:
171+
def override_keys(self) -> list[str]:
172172
return [k.lower() for k in self.overrides]

src/mxdev/hooks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ def load_hooks() -> list:
3030
return [ep.load()() for ep in load_eps_by_group("mxdev") if ep.name == "hook"]
3131

3232

33-
def read_hooks(state: State, hooks: typing.List[Hook]) -> None:
33+
def read_hooks(state: State, hooks: list[Hook]) -> None:
3434
for hook in hooks:
3535
hook.read(state)
3636

3737

38-
def write_hooks(state: State, hooks: typing.List[Hook]) -> None:
38+
def write_hooks(state: State, hooks: list[Hook]) -> None:
3939
for hook in hooks:
4040
hook.write(state)

src/mxdev/including.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111

1212
def resolve_dependencies(
13-
file_or_url: typing.Union[str, Path],
13+
file_or_url: str | Path,
1414
tmpdir: str,
1515
http_parent=None,
16-
) -> typing.List[Path]:
16+
) -> list[Path]:
1717
"""Resolve dependencies of a file or url
1818
1919
The result is a list of Path objects, starting with the
@@ -69,7 +69,7 @@ def resolve_dependencies(
6969
return file_list
7070

7171

72-
def read_with_included(file_or_url: typing.Union[str, Path]) -> ConfigParser:
72+
def read_with_included(file_or_url: str | Path) -> ConfigParser:
7373
"""Read a file or url and include all referenced files,
7474
7575
Parse the result as a ConfigParser and return it.

src/mxdev/processing.py

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414
def process_line(
1515
line: str,
16-
package_keys: typing.List[str],
17-
override_keys: typing.List[str],
18-
ignore_keys: typing.List[str],
16+
package_keys: list[str],
17+
override_keys: list[str],
18+
ignore_keys: list[str],
1919
variety: str,
20-
) -> typing.Tuple[typing.List[str], typing.List[str]]:
20+
) -> tuple[list[str], list[str]]:
2121
"""Take line from a constraints or requirements file and process it recursively.
2222
2323
The line is taken as is unless one of the following cases matches:
@@ -69,11 +69,11 @@ def process_line(
6969

7070
def process_io(
7171
fio: typing.IO,
72-
requirements: typing.List[str],
73-
constraints: typing.List[str],
74-
package_keys: typing.List[str],
75-
override_keys: typing.List[str],
76-
ignore_keys: typing.List[str],
72+
requirements: list[str],
73+
constraints: list[str],
74+
package_keys: list[str],
75+
override_keys: list[str],
76+
ignore_keys: list[str],
7777
variety: str,
7878
) -> None:
7979
"""Read lines from an open file and trigger processing of each line
@@ -91,17 +91,17 @@ def process_io(
9191

9292
def resolve_dependencies(
9393
file_or_url: str,
94-
package_keys: typing.List[str],
95-
override_keys: typing.List[str],
96-
ignore_keys: typing.List[str],
94+
package_keys: list[str],
95+
override_keys: list[str],
96+
ignore_keys: list[str],
9797
variety: str = "r",
98-
) -> typing.Tuple[typing.List[str], typing.List[str]]:
98+
) -> tuple[list[str], list[str]]:
9999
"""Takes a file or url, loads it and trigger to recursivly processes its content.
100100
101101
returns tuple of requirements and constraints
102102
"""
103-
requirements: typing.List[str] = []
104-
constraints: typing.List[str] = []
103+
requirements: list[str] = []
104+
constraints: list[str] = []
105105
if not file_or_url.strip():
106106
logger.info("mxdev is configured to run without input requirements!")
107107
return ([], [])
@@ -210,7 +210,7 @@ def fetch(state: State) -> None:
210210
)
211211

212212

213-
def write_dev_sources(fio, packages: typing.Dict[str, typing.Dict[str, typing.Any]]):
213+
def write_dev_sources(fio, packages: dict[str, dict[str, typing.Any]]):
214214
"""Create requirements configuration for fetched source packages."""
215215
if not packages:
216216
return
@@ -231,9 +231,7 @@ def write_dev_sources(fio, packages: typing.Dict[str, typing.Dict[str, typing.An
231231
fio.write("\n\n")
232232

233233

234-
def write_dev_overrides(
235-
fio, overrides: typing.Dict[str, str], package_keys: typing.List[str]
236-
):
234+
def write_dev_overrides(fio, overrides: dict[str, str], package_keys: list[str]):
237235
"""Create requirements configuration for overridden packages."""
238236
fio.write("#" * 79 + "\n")
239237
fio.write("# mxdev constraint overrides\n")
@@ -247,7 +245,7 @@ def write_dev_overrides(
247245
fio.write("\n\n")
248246

249247

250-
def write_main_package(fio, settings: typing.Dict[str, str]):
248+
def write_main_package(fio, settings: dict[str, str]):
251249
"""Write main package if configured."""
252250
main_package = settings.get("main-package")
253251
if main_package:

src/mxdev/state.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
@dataclass
99
class State:
1010
configuration: Configuration
11-
requirements: typing.List[str] = field(default_factory=list)
12-
constraints: typing.List[str] = field(default_factory=list)
11+
requirements: list[str] = field(default_factory=list)
12+
constraints: list[str] = field(default_factory=list)

0 commit comments

Comments
 (0)