Skip to content

Commit 2669d72

Browse files
authored
Support Python 3.12 (#735)
Fixes #734
1 parent 190edf1 commit 2669d72

File tree

11 files changed

+54
-44
lines changed

11 files changed

+54
-44
lines changed

.github/workflows/run-tests.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
strategy:
1717
matrix:
1818
os: [ubuntu-latest]
19-
version: ['3.8', '3.9', '3.10', '3.11']
19+
version: ['3.8', '3.9', '3.10', '3.11', '3.12']
2020
include:
2121
- version: '3.8'
2222
tox-env: py38,py38-mypy,py38-lint,safety
@@ -25,13 +25,15 @@ jobs:
2525
- version: '3.10'
2626
tox-env: py310,py310-mypy,py310-lint,safety
2727
- version: '3.11'
28-
tox-env: py311,py311-mypy,py311-lint,format,safety
28+
tox-env: py311,py311-mypy,py311-lint,safety
29+
- version: '3.12'
30+
tox-env: py312,py312-mypy,format,safety
2931
- os: windows-latest
30-
version: '3.11'
31-
tox-env: py311,safety
32+
version: '3.12'
33+
tox-env: py312,safety
3234
- os: macos-latest
33-
version: '3.11'
34-
tox-env: py311,safety
35+
version: '3.12'
36+
tox-env: py312,safety
3537
steps:
3638
- uses: actions/checkout@v3
3739
- uses: actions/setup-python@v4

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
### Added
99
* Added rudimentary support for `clojure.stacktrace` with `print-cause-trace` (part of #721)
1010
* Added support for `bytes` literals using a `#b` prefix (#732)
11+
* Added support for Python 3.12 (#734)
1112

1213
### Changed
1314
* Basilisp now supports PyTest 7.0+ (#660)

docs/pyinterop.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ When compiled, a ``kebab-case`` identifier always becomes a ``snake_case`` ident
2727
Python Builtins
2828
---------------
2929

30-
Python features a collection of `builtin <https://docs.python.org/3.8/library/functions.html>`_ functions which are available by default without module qualification in all Python scripts.
30+
Python features a collection of `builtin <https://docs.python.org/3/library/functions.html>`_ functions which are available by default without module qualification in all Python scripts.
3131
Python builtins are available in all Basilisp code as qualified symbols with the ``python`` namespace portion.
3232
It is not required to import anything to enable this functionality.
3333

pyproject.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ classifiers = [
2222
"Programming Language :: Python :: 3.9",
2323
"Programming Language :: Python :: 3.10",
2424
"Programming Language :: Python :: 3.11",
25+
"Programming Language :: Python :: 3.12",
2526
"Programming Language :: Python :: Implementation :: CPython",
2627
"Programming Language :: Python :: Implementation :: PyPy",
2728
"Topic :: Software Development :: Compilers",
@@ -31,7 +32,7 @@ include = ["README.md", "LICENSE"]
3132
[tool.poetry.dependencies]
3233
python = "^3.8"
3334
attrs = ">=20.1.0"
34-
immutables = "^0.15"
35+
immutables = "^0.20"
3536
prompt-toolkit = "^3.0.0"
3637
pyrsistent = "^0.18.0"
3738
python-dateutil = "^2.8.1"
@@ -68,7 +69,7 @@ build-backend = "poetry.core.masonry.api"
6869

6970
[tool.black]
7071
line-length = 88
71-
target-version = ["py36"]
72+
target-version = ["py38"]
7273
include = '\.pyi?$'
7374
exclude = '''
7475
/(
@@ -148,10 +149,8 @@ warn_unused_ignores = true
148149
module = [
149150
"astor.*",
150151
"prompt_toolkit.*",
151-
"py.*",
152152
"pygments.*",
153153
"pytest.*",
154-
"_pytest.*",
155154
"sphinx.*"
156155
]
157156
ignore_missing_imports = true

src/basilisp/lang/map.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Callable, Iterable, Mapping, Optional, Tuple, TypeVar, Union, cast
33

44
from immutables import Map as _Map
5+
from immutables import MapMutation
56

67
from basilisp.lang.interfaces import (
78
IEvolveableCollection,
@@ -18,12 +19,6 @@
1819
from basilisp.lang.vector import MapEntry
1920
from basilisp.util import partition
2021

21-
try:
22-
from immutables._map import MapMutation
23-
except ImportError:
24-
from immutables.map import MapMutation # type: ignore[assignment]
25-
26-
2722
T = TypeVar("T")
2823
K = TypeVar("K")
2924
V = TypeVar("V")
@@ -208,7 +203,7 @@ def update(self, *maps: Mapping[K, V]) -> "PersistentMap":
208203
m: _Map = self._inner.update(*(m.items() for m in maps))
209204
return PersistentMap(m)
210205

211-
def update_with(
206+
def update_with( # type: ignore[return]
212207
self, merge_fn: Callable[[V, V], V], *maps: Mapping[K, V]
213208
) -> "PersistentMap[K, V]":
214209
with self._inner.mutate() as m:
@@ -217,7 +212,7 @@ def update_with(
217212
m.set(k, merge_fn(m[k], v) if k in m else v)
218213
return PersistentMap(m.finish())
219214

220-
def cons( # type: ignore[override]
215+
def cons( # type: ignore[override, return]
221216
self,
222217
*elems: Union[
223218
IPersistentMap[K, V],
@@ -279,7 +274,7 @@ def m(**kvs) -> PersistentMap[str, V]:
279274
return PersistentMap.from_coll(kvs)
280275

281276

282-
def from_entries(entries: Iterable[MapEntry[K, V]]) -> PersistentMap[K, V]:
277+
def from_entries(entries: Iterable[MapEntry[K, V]]) -> PersistentMap[K, V]: # type: ignore[return]
283278
with _Map().mutate() as m: # type: ignore[var-annotated]
284279
for entry in entries:
285280
m.set(entry.key, entry.value)

src/basilisp/lang/runtime.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
NS_VAR_SYM = sym.symbol(NS_VAR_NAME, ns=CORE_NS)
7272
NS_VAR_NS = CORE_NS
7373
REPL_DEFAULT_NS = "basilisp.user"
74-
SUPPORTED_PYTHON_VERSIONS = frozenset({(3, 8), (3, 9), (3, 10), (3, 11)})
74+
SUPPORTED_PYTHON_VERSIONS = frozenset({(3, 8), (3, 9), (3, 10), (3, 11), (3, 12)})
7575

7676
# Public basilisp.core symbol names
7777
COMPILER_OPTIONS_VAR_NAME = "*compiler-options*"

src/basilisp/lang/set.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import AbstractSet, Iterable, Optional, TypeVar
33

44
from immutables import Map as _Map
5+
from immutables import MapMutation
56

67
from basilisp.lang.interfaces import (
78
IEvolveableCollection,
@@ -15,12 +16,6 @@
1516
from basilisp.lang.obj import seq_lrepr as _seq_lrepr
1617
from basilisp.lang.seq import sequence
1718

18-
try:
19-
from immutables._map import MapMutation
20-
except ImportError:
21-
from immutables.map import MapMutation # type: ignore[assignment]
22-
23-
2419
T = TypeVar("T")
2520

2621

@@ -153,13 +148,13 @@ def meta(self) -> Optional[IPersistentMap]:
153148
def with_meta(self, meta: Optional[IPersistentMap]) -> "PersistentSet[T]":
154149
return set(self._inner, meta=meta)
155150

156-
def cons(self, *elems: T) -> "PersistentSet[T]":
151+
def cons(self, *elems: T) -> "PersistentSet[T]": # type: ignore[return]
157152
with self._inner.mutate() as m:
158153
for elem in elems:
159154
m.set(elem, elem)
160155
return PersistentSet(m.finish(), meta=self.meta)
161156

162-
def disj(self, *elems: T) -> "PersistentSet[T]":
157+
def disj(self, *elems: T) -> "PersistentSet[T]": # type: ignore[return]
163158
with self._inner.mutate() as m:
164159
for elem in elems:
165160
try:

tests/basilisp/compiler_test.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from unittest.mock import Mock
1212

1313
import pytest
14-
from _pytest.monkeypatch import MonkeyPatch
1514
from dateutil import parser as dateparser
1615

1716
from basilisp.lang import compiler as compiler
@@ -5402,7 +5401,7 @@ def test_local_deftype_staticmethod_resolves(self, lcompile: CompileFn):
54025401
lcompile("(Point/do-non-static 1 2)")
54035402

54045403
def test_aliased_namespace_not_hidden_by_python_module(
5405-
self, lcompile: CompileFn, monkeypatch: MonkeyPatch
5404+
self, lcompile: CompileFn, monkeypatch: pytest.MonkeyPatch
54065405
):
54075406
with TemporaryDirectory() as tmpdir:
54085407
cwd = os.getcwd()

tests/basilisp/runtime_test.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def test_is_supported_python_version():
3939
"lpy39-",
4040
"lpy310-",
4141
"lpy311-",
42+
"lpy312-",
4243
],
4344
)
4445
),
@@ -54,6 +55,7 @@ def test_is_supported_python_version():
5455
"lpy38+",
5556
"lpy310-",
5657
"lpy311-",
58+
"lpy312-",
5759
],
5860
)
5961
),
@@ -64,6 +66,7 @@ def test_is_supported_python_version():
6466
"lpy310",
6567
"default",
6668
"lpy",
69+
"lpy312-",
6770
"lpy311-",
6871
"lpy310+",
6972
"lpy310-",
@@ -80,13 +83,30 @@ def test_is_supported_python_version():
8083
"default",
8184
"lpy",
8285
"lpy311+",
86+
"lpy312-",
8387
"lpy311-",
8488
"lpy310+",
8589
"lpy39+",
8690
"lpy38+",
8791
],
8892
)
8993
),
94+
(3, 12): frozenset(
95+
map(
96+
kw.keyword,
97+
[
98+
"lpy312",
99+
"default",
100+
"lpy",
101+
"lpy311+",
102+
"lpy312+",
103+
"lpy312-",
104+
"lpy311+",
105+
"lpy39+",
106+
"lpy38+",
107+
],
108+
)
109+
),
90110
}[(sys.version_info.major, sys.version_info.minor)],
91111
)
92112
def test_reader_default_featureset(feature):

tests/basilisp/testrunner_test.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22
import sys
33

44
import pytest
5-
from _pytest.pytester import Pytester, RunResult
65

76
from basilisp.lang import runtime
87
from basilisp.lang import symbol as sym
98

109

1110
class TestTestrunner:
1211
@pytest.fixture
13-
def run_result(self, pytester: Pytester) -> RunResult:
12+
def run_result(self, pytester: pytest.Pytester) -> pytest.RunResult:
1413
code = """
1514
(ns test-testrunner
1615
(:require
@@ -44,10 +43,10 @@ def run_result(self, pytester: Pytester) -> RunResult:
4443
yield pytester.runpytest()
4544
runtime.Namespace.remove(sym.symbol("test-testrunner"))
4645

47-
def test_outcomes(self, run_result: RunResult):
46+
def test_outcomes(self, run_result: pytest.RunResult):
4847
run_result.assert_outcomes(passed=1, failed=2)
4948

50-
def test_failure_repr(self, run_result: RunResult):
49+
def test_failure_repr(self, run_result: pytest.RunResult):
5150
run_result.stdout.fnmatch_lines(
5251
[
5352
"FAIL in (assertion-test) (test_testrunner.lpy:8)",
@@ -89,7 +88,7 @@ def test_failure_repr(self, run_result: RunResult):
8988
"further investigation."
9089
),
9190
)
92-
def test_error_repr(self, run_result: RunResult):
91+
def test_error_repr(self, run_result: pytest.RunResult):
9392
if sys.version_info < (3, 11):
9493
expected = [
9594
"ERROR in (assertion-test) (test_testrunner.lpy:12)",
@@ -126,7 +125,7 @@ def test_error_repr(self, run_result: RunResult):
126125
)
127126

128127

129-
def test_fixtures(pytester: Pytester):
128+
def test_fixtures(pytester: pytest.Pytester):
130129
code = """
131130
(ns test-fixtures
132131
(:require
@@ -167,7 +166,7 @@ def test_fixtures(pytester: Pytester):
167166
"""
168167
pytester.makefile(".lpy", test_fixtures=code)
169168
pytester.syspathinsert()
170-
result: pytester.RunResult = pytester.runpytest()
169+
result: pytest.RunResult = pytester.runpytest()
171170
result.assert_outcomes(passed=1, failed=1)
172171

173172
get_volatile = lambda vname: runtime.Var.find_safe(
@@ -189,7 +188,7 @@ def test_fixtures(pytester: Pytester):
189188
],
190189
)
191190
def test_fixtures_with_errors(
192-
pytester: Pytester,
191+
pytester: pytest.Pytester,
193192
fixture: str,
194193
style: str,
195194
errors: int,
@@ -219,5 +218,5 @@ def test_fixtures_with_errors(
219218
"""
220219
pytester.makefile(".lpy", test_fixtures_with_errors=code)
221220
pytester.syspathinsert()
222-
result: pytester.RunResult = pytester.runpytest()
221+
result: pytest.RunResult = pytester.runpytest()
223222
result.assert_outcomes(passed=passes, failed=failures, errors=errors)

0 commit comments

Comments
 (0)