Skip to content

Commit 2aad885

Browse files
committed
Drop support for Python versions before 3.10
1 parent 831da80 commit 2aad885

17 files changed

Lines changed: 153 additions & 635 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
# - Update macos images to at least 14 as 13 is retired
5050
# - Update ubuntu images
5151
os: [ubuntu-22.04, ubuntu-22.04-arm, windows-latest, macos-13]
52-
python: ['3.14', '3.13', '3.12', '3.11', '3.10', '3.9', '3.8'] # pypy3
52+
python: ['3.14', '3.13', '3.12', '3.11', '3.10'] # pypy3
5353

5454
steps:
5555
- name: Set Environment on macOS

clr_loader/__init__.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1+
from collections.abc import Sequence
12
from pathlib import Path
23
from tempfile import TemporaryDirectory
3-
from typing import Dict, Optional, Sequence
44

5-
from .types import Assembly, Runtime, RuntimeInfo
6-
from .util import StrOrPath
5+
from .types import Assembly, Runtime, RuntimeInfo, StrOrPath
76
from .util.find import find_dotnet_root, find_libmono, find_runtimes
87
from .util.runtime_spec import DotnetCoreRuntimeSpec
98

@@ -24,17 +23,17 @@
2423
def get_mono(
2524
*,
2625
# domain: Optional[str] = None,
27-
config_file: Optional[StrOrPath] = None,
28-
global_config_file: Optional[StrOrPath] = None,
29-
libmono: Optional[StrOrPath] = None,
26+
config_file: StrOrPath | None = None,
27+
global_config_file: StrOrPath | None = None,
28+
libmono: StrOrPath | None = None,
3029
sgen: bool = True,
3130
debug: bool = False,
32-
jit_options: Optional[Sequence[str]] = None,
33-
assembly_dir: Optional[str] = None,
34-
config_dir: Optional[str] = None,
31+
jit_options: Sequence[str] | None = None,
32+
assembly_dir: StrOrPath | None = None,
33+
config_dir: StrOrPath | None = None,
3534
set_signal_chaining: bool = False,
36-
trace_mask: Optional[str] = None,
37-
trace_level: Optional[str] = None,
35+
trace_mask: str | None = None,
36+
trace_level: str | None = None,
3837
) -> Runtime:
3938
"""Get a Mono runtime instance
4039
@@ -92,12 +91,12 @@ def get_mono(
9291

9392
def get_coreclr(
9493
*,
95-
runtime_config: Optional[StrOrPath] = None,
96-
entry_dll: Optional[StrOrPath] = None,
97-
dotnet_root: Optional[StrOrPath] = None,
98-
properties: Optional[Dict[str, str]] = None,
99-
runtime_spec: Optional[DotnetCoreRuntimeSpec] = None,
100-
runtime_version: Optional[str] = None,
94+
runtime_config: StrOrPath | None = None,
95+
entry_dll: StrOrPath | None = None,
96+
dotnet_root: StrOrPath | None = None,
97+
properties: dict[str, str] | None = None,
98+
runtime_spec: DotnetCoreRuntimeSpec | None = None,
99+
runtime_version: str | None = None,
101100
) -> Runtime:
102101
"""Get a CoreCLR (.NET Core) runtime instance
103102
@@ -179,7 +178,7 @@ def get_coreclr(
179178

180179

181180
def get_netfx(
182-
*, domain: Optional[str] = None, config_file: Optional[StrOrPath] = None
181+
*, domain: str | None = None, config_file: StrOrPath | None = None
183182
) -> Runtime:
184183
"""Get a .NET Framework runtime instance
185184
@@ -197,7 +196,7 @@ def get_netfx(
197196
return impl
198197

199198

200-
def _maybe_path(p: Optional[StrOrPath]) -> Optional[Path]:
199+
def _maybe_path(p: StrOrPath | None) -> Path | None:
201200
if p is None:
202201
return None
203202
else:

clr_loader/ffi/__init__.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import sys
22
from pathlib import Path
3-
from typing import Optional, Tuple
43

5-
import cffi # type: ignore
4+
import cffi
65

76
from . import hostfxr, mono, netfx
87

98
__all__ = ["ffi", "load_hostfxr", "load_mono", "load_netfx"]
109

11-
ffi = cffi.FFI() # type: ignore
10+
ffi = cffi.FFI()
1211

1312
for cdef in hostfxr.cdef + mono.cdef + netfx.cdef:
1413
ffi.cdef(cdef)
@@ -22,7 +21,7 @@ def load_hostfxr(dotnet_root: Path):
2221
hostfxr_path = dotnet_root / "host" / "fxr"
2322
hostfxr_paths = hostfxr_path.glob(f"*/{hostfxr_name}")
2423

25-
error_report = list()
24+
error_report: list[str] = []
2625

2726
for hostfxr_path in reversed(sorted(hostfxr_paths, key=_path_to_version)):
2827
try:
@@ -41,7 +40,7 @@ def load_hostfxr(dotnet_root: Path):
4140
)
4241

4342

44-
def load_mono(path: Optional[Path] = None):
43+
def load_mono(path: Path | None = None):
4544
# Preload C++ standard library, Mono needs that and doesn't properly link against it
4645
if sys.platform == "linux":
4746
ffi.dlopen("stdc++", ffi.RTLD_GLOBAL)
@@ -65,7 +64,7 @@ def load_netfx():
6564
return ffi.dlopen(str(path))
6665

6766

68-
def _path_to_version(path: Path) -> Tuple[int, int, int]:
67+
def _path_to_version(path: Path) -> tuple[int, int, int]:
6968
name = path.parent.name
7069
try:
7170
# Handle pre-release versions like "10.0.0-rc.1" by taking only the version part

clr_loader/hostfxr.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sys
22
from pathlib import Path
3-
from typing import Generator, Tuple, Optional
3+
from collections.abc import Generator
44

55
from .ffi import ffi, load_hostfxr
66
from .types import Runtime, RuntimeInfo, StrOrPath
@@ -18,8 +18,8 @@ def __init__(
1818
self,
1919
*,
2020
dotnet_root: Path,
21-
runtime_config: Optional[Path] = None,
22-
entry_dll: Optional[Path] = None,
21+
runtime_config: Path | None = None,
22+
entry_dll: Path | None = None,
2323
**params: str,
2424
):
2525
self._handle = None
@@ -81,7 +81,7 @@ def __setitem__(self, key: str, value: str) -> None:
8181
)
8282
check_result(res)
8383

84-
def __iter__(self) -> Generator[Tuple[str, str], None, None]:
84+
def __iter__(self) -> Generator[tuple[str, str], None, None]:
8585
if self.is_shutdown:
8686
raise RuntimeError("Runtime is shut down")
8787
max_size = 100

clr_loader/mono.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import atexit
22
import re
33
from pathlib import Path
4-
from typing import Any, Dict, Optional, Sequence
4+
from typing import Any
5+
from collections.abc import Sequence
56

67
from .ffi import ffi, load_mono
78
from .types import Runtime, RuntimeInfo, StrOrPath
@@ -17,20 +18,20 @@
1718
class Mono(Runtime):
1819
def __init__(
1920
self,
20-
libmono: Optional[Path],
21+
libmono: Path | None,
2122
*,
22-
domain: Optional[str] = None,
23+
domain: str | None = None,
2324
debug: bool = False,
24-
jit_options: Optional[Sequence[str]] = None,
25-
config_file: Optional[Path] = None,
26-
global_config_file: Optional[Path] = None,
27-
assembly_dir: Optional[str] = None,
28-
config_dir: Optional[str] = None,
25+
jit_options: Sequence[str] | None = None,
26+
config_file: Path | None = None,
27+
global_config_file: Path | None = None,
28+
assembly_dir: StrOrPath | None = None,
29+
config_dir: StrOrPath | None = None,
2930
set_signal_chaining: bool = False,
30-
trace_mask: Optional[str] = None,
31-
trace_level: Optional[str] = None,
31+
trace_mask: str | None = None,
32+
trace_level: str | None = None,
3233
):
33-
self._assemblies: Dict[Path, Any] = {}
34+
self._assemblies: dict[Path, Any] = {}
3435

3536
self._version: str = initialize(
3637
config_file=optional_path_as_string(config_file),
@@ -129,16 +130,16 @@ def __call__(self, ptr, size):
129130

130131

131132
def initialize(
132-
libmono: Optional[Path],
133+
libmono: Path | None,
133134
debug: bool = False,
134-
jit_options: Optional[Sequence[str]] = None,
135-
config_file: Optional[str] = None,
136-
global_config_file: Optional[str] = None,
137-
assembly_dir: Optional[str] = None,
138-
config_dir: Optional[str] = None,
135+
jit_options: Sequence[str] | None = None,
136+
config_file: str | None = None,
137+
global_config_file: str | None = None,
138+
assembly_dir: StrOrPath | None = None,
139+
config_dir: StrOrPath | None = None,
139140
set_signal_chaining: bool = False,
140-
trace_mask: Optional[str] = None,
141-
trace_level: Optional[str] = None,
141+
trace_mask: str | None = None,
142+
trace_level: str | None = None,
142143
) -> str:
143144
global _MONO, _ROOT_DOMAIN
144145
if _MONO is None:
@@ -151,7 +152,10 @@ def initialize(
151152
_MONO.mono_trace_set_level_string(trace_level.encode("utf8"))
152153

153154
if assembly_dir is not None and config_dir is not None:
154-
_MONO.mono_set_dirs(assembly_dir.encode("utf8"), config_dir.encode("utf8"))
155+
_MONO.mono_set_dirs(
156+
path_as_string(assembly_dir).encode("utf8"),
157+
path_as_string(config_dir).encode("utf8"),
158+
)
155159

156160
# Load in global config (i.e /etc/mono/config)
157161
global_encoded = global_config_file or ffi.NULL

clr_loader/netfx.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import atexit
22
from pathlib import Path
3-
from typing import Any, Optional
3+
from typing import Any
44

55
from .ffi import ffi, load_netfx
66
from .types import Runtime, RuntimeInfo, StrOrPath
@@ -9,10 +9,8 @@
99

1010

1111
class NetFx(Runtime):
12-
def __init__(
13-
self, domain: Optional[str] = None, config_file: Optional[Path] = None
14-
):
15-
self._domain: Optional[str] = None
12+
def __init__(self, domain: str | None = None, config_file: Path | None = None):
13+
self._domain: str | None = None
1614

1715
initialize()
1816
if config_file is not None:
@@ -22,8 +20,8 @@ def __init__(
2220

2321
domain_s = domain.encode("utf8") if domain else ffi.NULL
2422

25-
self._domain_name: Optional[str] = domain
26-
self._config_file: Optional[Path] = config_file
23+
self._domain_name: str | None = domain
24+
self._config_file: Path | None = config_file
2725
self._domain = _FW.pyclr_create_appdomain(domain_s, config_file_s)
2826

2927
def info(self) -> RuntimeInfo:

clr_loader/types.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
from abc import ABCMeta, abstractmethod
22
from dataclasses import dataclass, field
33
from os import PathLike
4-
from typing import Any, Callable, Dict, Optional, Union
4+
from typing import Any
5+
from collections.abc import Callable
56

67
__all__ = ["StrOrPath"]
78

8-
try:
9-
StrOrPath = Union[str, PathLike[str]]
10-
except TypeError:
11-
StrOrPath = Union[str, PathLike]
9+
StrOrPath = str | PathLike[str]
1210

1311

1412
@dataclass
@@ -33,7 +31,7 @@ class RuntimeInfo:
3331
version: str
3432
initialized: bool
3533
shutdown: bool
36-
properties: Dict[str, str] = field(repr=False)
34+
properties: dict[str, str] = field(repr=False)
3735

3836
def __str__(self) -> str:
3937
return (
@@ -75,7 +73,7 @@ def __init__(self, runtime: "Runtime", path: StrOrPath):
7573
self._runtime: "Runtime" = runtime
7674
self._path: StrOrPath = path
7775

78-
def get_function(self, name: str, func: Optional[str] = None) -> ClrFunction:
76+
def get_function(self, name: str, func: str | None = None) -> ClrFunction:
7977
"""Get a wrapped .NET function instance
8078
8179
The function must be ``static``, and it must have the signature

clr_loader/util/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from pathlib import Path
2-
from typing import Optional
32

43
from ..types import StrOrPath
54
from .clr_error import ClrError
@@ -15,7 +14,7 @@
1514
]
1615

1716

18-
def optional_path_as_string(path: Optional[StrOrPath]) -> Optional[str]:
17+
def optional_path_as_string(path: StrOrPath | None) -> str | None:
1918
if path is None:
2019
return None
2120
return path_as_string(path)

clr_loader/util/clr_error.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
from typing import Optional
2-
3-
41
class ClrError(Exception):
52
def __init__(
63
self,
74
hresult: int,
8-
name: Optional[str] = None,
9-
message: Optional[str] = None,
10-
comment: Optional[str] = None,
5+
name: str | None = None,
6+
message: str | None = None,
7+
comment: str | None = None,
118
):
129
self.hresult = hresult
1310
self.name = name

clr_loader/util/coreclr_errors.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
from typing import Dict, Optional
2-
31
from .clr_error import ClrError
42

53

6-
def get_coreclr_error(hresult: int) -> Optional[ClrError]:
4+
def get_coreclr_error(hresult: int) -> ClrError | None:
75
name = SymbolicName.get(hresult)
86
if not name:
97
return None
@@ -16,9 +14,9 @@ def get_coreclr_error(hresult: int) -> Optional[ClrError]:
1614
)
1715

1816

19-
Comment: Dict[int, str] = {}
20-
SymbolicName: Dict[int, str] = {}
21-
Message: Dict[int, str] = {}
17+
Comment: dict[int, str] = {}
18+
SymbolicName: dict[int, str] = {}
19+
Message: dict[int, str] = {}
2220

2321

2422
if __name__ == "__main__":
@@ -47,7 +45,7 @@ def get_coreclr_error(hresult: int) -> Optional[ClrError]:
4745

4846
marker = "# == Autogenerated from corerror.xml =="
4947

50-
with open(__file__, "r") as f:
48+
with open(__file__) as f:
5149
current = f.read()
5250
before, _, _ = current.rpartition(marker)
5351

0 commit comments

Comments
 (0)