Skip to content

Commit 5c4df15

Browse files
authored
Merge pull request #2710 from Kodiologist/py3-15
Support Python 3.15
2 parents 6c07aaf + 4fc9de4 commit 5c4df15

6 files changed

Lines changed: 28 additions & 11 deletions

File tree

.github/workflows/tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
matrix:
1313
name-prefix: ['']
1414
os: [ubuntu-latest]
15-
python: [3.9, '3.10', 3.11, 3.12, 3.13, 3.14, pypy-3.11]
15+
python: [3.9, '3.10', 3.11, 3.12, 3.13, 3.14, '>=3.15.0-beta.1', pypy-3.11]
1616
include:
1717
# To keep the overall number of runs low, we test Windows and MacOS
1818
# only on the latest CPython.

docs/cli.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,5 @@ hyc
6464

6565
.. warning::
6666
``hyc`` can execute arbitrary code (via macros, :hy:func:`eval-when-compile`, etc.). Don't give it untrusted input.
67+
68+
In practice, ``hyc`` is rarely useful, because Hy produces bytecode automatically. It exists mostly for historical reasons, and may be removed in a future major release of Hy.

hy/compat.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
PY3_12_6 = sys.version_info >= (3, 12, 6)
99
PY3_13 = sys.version_info >= (3, 13)
1010
PY3_14 = sys.version_info >= (3, 14)
11+
PY3_15 = sys.version_info >= (3, 15)
1112
PYPY = platform.python_implementation() == "PyPy"
1213

1314

hy/importer.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,19 @@ def _hy_code_from_file(filename, loader_type=None):
7777
return code
7878

7979

80-
def _get_code_from_file(run_name, fname=None, hy_src_check=lambda x: x.endswith(".hy")):
80+
def _get_code_from_file(*args, hy_src_check=lambda x: x.endswith(".hy")):
8181
"""A patch of `runpy._get_code_from_file` that will also run and cache Hy
8282
code.
8383
"""
84-
if fname is None and run_name is not None:
85-
fname = run_name
84+
85+
if hy.compat.PY3_15:
86+
fname, module = args
87+
elif hy.compat.PY3_12:
88+
fname, = args
89+
else:
90+
run_name, fname = args
91+
if fname is None and run_name is not None:
92+
fname = run_name
8693

8794
# Check for bytecode first. (This is what the `runpy` version does!)
8895
with open(fname, "rb") as f:
@@ -97,7 +104,9 @@ def _get_code_from_file(run_name, fname=None, hy_src_check=lambda x: x.endswith(
97104
# This code differs from `runpy`'s only in that we
98105
# force decoding into UTF-8.
99106
source = f.read().decode("utf-8")
100-
code = compile(source, fname, "exec")
107+
code = compile(
108+
source, fname, "exec",
109+
**(dict(module=module) if hy.compat.PY3_15 else {}))
101110

102111
return code if hy.compat.PY3_12_6 else (code, fname)
103112

@@ -113,7 +122,7 @@ def _could_be_hy_src(filename):
113122
)
114123

115124

116-
def _hy_source_to_code(self, data, path, _optimize=-1):
125+
def _hy_source_to_code(self, data, path, fullname=None, _optimize=-1):
117126
if _could_be_hy_src(path):
118127
if os.environ.get("HY_MESSAGE_WHEN_COMPILING"):
119128
print("Compiling", path, file=sys.stderr)
@@ -122,7 +131,10 @@ def _hy_source_to_code(self, data, path, _optimize=-1):
122131
with loader_module_obj(self) as module:
123132
data = hy_compile(hy_tree, module)
124133

125-
return _py_source_to_code(self, data, path, _optimize=_optimize)
134+
return _py_source_to_code(
135+
self, data, path,
136+
_optimize=_optimize,
137+
**(dict(fullname=fullname) if hy.compat.PY3_15 else {}))
126138

127139

128140
importlib.machinery.SourceFileLoader.source_to_code = _hy_source_to_code
@@ -132,9 +144,9 @@ def _hy_source_to_code(self, data, path, _optimize=-1):
132144
zipimport._zip_searchorder += ((".hy", False, False),)
133145
_py_compile_source = zipimport._compile_source
134146

135-
def _hy_compile_source(pathname, source):
147+
def _hy_compile_source(pathname, source, module=None):
136148
if not pathname.endswith(".hy"):
137-
return _py_compile_source(pathname, source)
149+
return _py_compile_source(pathname, source, module)
138150
mname = f"<zip:{pathname}>"
139151
sys.modules[mname] = types.ModuleType(mname)
140152
return compile(

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def run(self):
3737
version='0.0.0',
3838
setup_requires=["wheel"] + requires,
3939
install_requires=requires,
40-
python_requires=">= 3.9, < 3.15",
40+
python_requires=">= 3.9, < 3.16",
4141
entry_points={
4242
"console_scripts": [
4343
"hy = hy.cmdline:hy_main",

tests/native_tests/repl.hy

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@
121121
; https://github.com/hylang/hy/issues/2004
122122
(assert (has
123123
(rt "(defn foo [/])\n(defn bar [a a])" 'err)
124-
"SyntaxError: duplicate argument"))
124+
"SyntaxError: duplicate "))
125+
; It may say "duplicate argument" or "duplicate parameter",
126+
; depending on the Python version.
125127
; https://github.com/hylang/hy/issues/2014
126128
(setv err (rt "(defn foo []\n(import re *))" 'err))
127129
(assert (has err "SyntaxError: import * only allowed"))

0 commit comments

Comments
 (0)