Skip to content

Commit f9c0797

Browse files
maycuatroi1odashi
andauthored
Pump Version python to 3.12, 3.13. Allow pip install for python 3.12, 3.13 (#210)
* - Update python version to 3.12 * - Update python version to 3.12 - Improve CI libraries * - Test for python 3.13 - Remove ORL python 3.8, 3.9 - Fix CI unit-test * - update python version readme * - remove assign exception as e Co-authored-by: Yusuke Oda <[email protected]> * - remove if condition for python lower than 3.8 * - remove condition because python always >= 3.9 * - Create new function `ast_function_def` to handle `type_params` for python 3.12 - Fix CI for python 3.11. * - Remove testcase for python 3.7 * - change to import module Co-authored-by: Yusuke Oda <[email protected]> * - Fix coding convention * - fix isort * - Refactor function `create_function_def` * - remove un-used test case * - remove un-used test case * - remove un-used test case --------- Co-authored-by: Yusuke Oda <[email protected]>
1 parent 678cd0e commit f9c0797

17 files changed

+271
-236
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
15+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
1616
steps:
1717
- uses: actions/checkout@v3
1818
- name: Set up Python ${{ matrix.python-version }}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ corresponding $\LaTeX$ expression:
2121

2222
1. *Which Python versions are supported?*
2323

24-
Syntaxes on **Pythons 3.7 to 3.11** are officially supported, or will be supported.
24+
Syntaxes on **Pythons 3.9 to 3.13** are officially supported, or will be supported.
2525

2626
2. *Which technique is used?*
2727

pyproject.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
88
name = "latexify-py"
99
description = "Generates LaTeX math description from Python functions."
1010
readme = "README.md"
11-
requires-python = ">=3.7, <3.12"
11+
requires-python = ">=3.9, <3.14"
1212
license = {text = "Apache Software License 2.0"}
1313
authors = [
1414
{name = "Yusuke Oda", email = "[email protected]"}
@@ -24,11 +24,11 @@ classifiers = [
2424
"Framework :: IPython",
2525
"Framework :: Jupyter",
2626
"License :: OSI Approved :: Apache Software License",
27-
"Programming Language :: Python :: 3.7",
28-
"Programming Language :: Python :: 3.8",
2927
"Programming Language :: Python :: 3.9",
3028
"Programming Language :: Python :: 3.10",
3129
"Programming Language :: Python :: 3.11",
30+
"Programming Language :: Python :: 3.12",
31+
"Programming Language :: Python :: 3.13",
3232
"Topic :: Scientific/Engineering :: Mathematics",
3333
"Topic :: Software Development :: Code Generators",
3434
"Topic :: Text Processing :: Markup :: LaTeX",
@@ -43,17 +43,17 @@ dynamic = [
4343
[project.optional-dependencies]
4444
dev = [
4545
"build>=0.8",
46-
"black>=22.10",
47-
"flake8>=5.0",
46+
"black>=24.3",
47+
"flake8>=6.0",
4848
"isort>=5.10",
49-
"mypy>=0.991",
49+
"mypy>=1.9",
5050
"notebook>=6.5.1",
51-
"pyproject-flake8>=5.0",
51+
"pyproject-flake8>=6.0",
5252
"pytest>=7.1",
5353
"twine>=4.0",
5454
]
5555
mypy = [
56-
"mypy>=0.991",
56+
"mypy>=1.9",
5757
"pytest>=7.1",
5858
]
5959

src/latexify/analyzers_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from latexify import analyzers, ast_utils, exceptions, test_utils
1010

1111

12-
@test_utils.require_at_least(8)
1312
@pytest.mark.parametrize(
1413
"code,start,stop,step,start_int,stop_int,step_int",
1514
[

src/latexify/ast_utils.py

Lines changed: 75 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,24 +56,12 @@ def make_constant(value: Any) -> ast.expr:
5656
Raises:
5757
ValueError: Unsupported value type.
5858
"""
59-
if sys.version_info.minor < 8:
60-
if value is None or value is False or value is True:
61-
return ast.NameConstant(value=value)
62-
if value is ...:
63-
return ast.Ellipsis()
64-
if isinstance(value, (int, float, complex)):
65-
return ast.Num(n=value)
66-
if isinstance(value, str):
67-
return ast.Str(s=value)
68-
if isinstance(value, bytes):
69-
return ast.Bytes(s=value)
70-
else:
71-
if (
72-
value is None
73-
or value is ...
74-
or isinstance(value, (bool, int, float, complex, str, bytes))
75-
):
76-
return ast.Constant(value=value)
59+
if (
60+
value is None
61+
or value is ...
62+
or isinstance(value, (bool, int, float, complex, str, bytes))
63+
):
64+
return ast.Constant(value=value)
7765

7866
raise ValueError(f"Unsupported type to generate Constant: {type(value).__name__}")
7967

@@ -87,13 +75,7 @@ def is_constant(node: ast.AST) -> bool:
8775
Returns:
8876
True if the node is a constant, False otherwise.
8977
"""
90-
if sys.version_info.minor < 8:
91-
return isinstance(
92-
node,
93-
(ast.Bytes, ast.Constant, ast.Ellipsis, ast.NameConstant, ast.Num, ast.Str),
94-
)
95-
else:
96-
return isinstance(node, ast.Constant)
78+
return isinstance(node, ast.Constant)
9779

9880

9981
def is_str(node: ast.AST) -> bool:
@@ -120,20 +102,12 @@ def extract_int_or_none(node: ast.expr) -> int | None:
120102
Returns:
121103
Extracted int value, or None if extraction failed.
122104
"""
123-
if sys.version_info.minor < 8:
124-
if (
125-
isinstance(node, ast.Num)
126-
and isinstance(node.n, int)
127-
and not isinstance(node.n, bool)
128-
):
129-
return node.n
130-
else:
131-
if (
132-
isinstance(node, ast.Constant)
133-
and isinstance(node.value, int)
134-
and not isinstance(node.n, bool)
135-
):
136-
return node.value
105+
if (
106+
isinstance(node, ast.Constant)
107+
and isinstance(node.value, int)
108+
and not isinstance(node.value, bool)
109+
):
110+
return node.value
137111

138112
return None
139113

@@ -173,3 +147,65 @@ def extract_function_name_or_none(node: ast.Call) -> str | None:
173147
return node.func.attr
174148

175149
return None
150+
151+
152+
def create_function_def(
153+
name,
154+
args,
155+
body,
156+
decorator_list,
157+
returns=None,
158+
type_comment=None,
159+
type_params=None,
160+
lineno=None,
161+
col_offset=None,
162+
end_lineno=None,
163+
end_col_offset=None,
164+
) -> ast.FunctionDef:
165+
"""Creates a FunctionDef node.
166+
167+
This function generates an `ast.FunctionDef` node, optionally removing
168+
the `type_params` keyword argument for Python versions below 3.12.
169+
170+
Args:
171+
name: Name of the function.
172+
args: Arguments of the function.
173+
body: Body of the function.
174+
decorator_list: List of decorators.
175+
returns: Return type of the function.
176+
type_comment: Type comment of the function.
177+
type_params: Type parameters of the function.
178+
lineno: Line number of the function definition.
179+
col_offset: Column offset of the function definition.
180+
end_lineno: End line number of the function definition.
181+
end_col_offset: End column offset of the function definition.
182+
183+
Returns:
184+
ast.FunctionDef: The generated FunctionDef node.
185+
"""
186+
if sys.version_info.minor < 12:
187+
return ast.FunctionDef(
188+
name=name,
189+
args=args,
190+
body=body,
191+
decorator_list=decorator_list,
192+
returns=returns,
193+
type_comment=type_comment,
194+
lineno=lineno,
195+
col_offset=col_offset,
196+
end_lineno=end_lineno,
197+
end_col_offset=end_col_offset,
198+
) # type: ignore
199+
return ast.FunctionDef(
200+
name=name,
201+
args=args,
202+
body=body,
203+
decorator_list=decorator_list,
204+
returns=returns,
205+
type_comment=type_comment,
206+
type_params=type_params,
207+
lineno=lineno,
208+
col_offset=col_offset,
209+
end_lineno=end_lineno,
210+
end_col_offset=end_col_offset,
211+
) # type: ignore

src/latexify/ast_utils_test.py

Lines changed: 44 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import ast
6+
import sys
67
from typing import Any
78

89
import pytest
@@ -34,29 +35,6 @@ def test_make_attribute() -> None:
3435
)
3536

3637

37-
@test_utils.require_at_most(7)
38-
@pytest.mark.parametrize(
39-
"value,expected",
40-
[
41-
(None, ast.NameConstant(value=None)),
42-
(False, ast.NameConstant(value=False)),
43-
(True, ast.NameConstant(value=True)),
44-
(..., ast.Ellipsis()),
45-
(123, ast.Num(n=123)),
46-
(4.5, ast.Num(n=4.5)),
47-
(6 + 7j, ast.Num(n=6 + 7j)),
48-
("foo", ast.Str(s="foo")),
49-
(b"bar", ast.Bytes(s=b"bar")),
50-
],
51-
)
52-
def test_make_constant_legacy(value: Any, expected: ast.Constant) -> None:
53-
test_utils.assert_ast_equal(
54-
observed=ast_utils.make_constant(value),
55-
expected=expected,
56-
)
57-
58-
59-
@test_utils.require_at_least(8)
6038
@pytest.mark.parametrize(
6139
"value,expected",
6240
[
@@ -83,25 +61,6 @@ def test_make_constant_invalid() -> None:
8361
ast_utils.make_constant(object())
8462

8563

86-
@test_utils.require_at_most(7)
87-
@pytest.mark.parametrize(
88-
"value,expected",
89-
[
90-
(ast.Bytes(s=b"foo"), True),
91-
(ast.Constant("bar"), True),
92-
(ast.Ellipsis(), True),
93-
(ast.NameConstant(value=None), True),
94-
(ast.Num(n=123), True),
95-
(ast.Str(s="baz"), True),
96-
(ast.Expr(value=ast.Num(456)), False),
97-
(ast.Global(names=["qux"]), False),
98-
],
99-
)
100-
def test_is_constant_legacy(value: ast.AST, expected: bool) -> None:
101-
assert ast_utils.is_constant(value) is expected
102-
103-
104-
@test_utils.require_at_least(8)
10564
@pytest.mark.parametrize(
10665
"value,expected",
10766
[
@@ -114,25 +73,6 @@ def test_is_constant(value: ast.AST, expected: bool) -> None:
11473
assert ast_utils.is_constant(value) is expected
11574

11675

117-
@test_utils.require_at_most(7)
118-
@pytest.mark.parametrize(
119-
"value,expected",
120-
[
121-
(ast.Bytes(s=b"foo"), False),
122-
(ast.Constant("bar"), True),
123-
(ast.Ellipsis(), False),
124-
(ast.NameConstant(value=None), False),
125-
(ast.Num(n=123), False),
126-
(ast.Str(s="baz"), True),
127-
(ast.Expr(value=ast.Num(456)), False),
128-
(ast.Global(names=["qux"]), False),
129-
],
130-
)
131-
def test_is_str_legacy(value: ast.AST, expected: bool) -> None:
132-
assert ast_utils.is_str(value) is expected
133-
134-
135-
@test_utils.require_at_least(8)
13676
@pytest.mark.parametrize(
13777
"value,expected",
13878
[
@@ -194,6 +134,7 @@ def test_extract_int_invalid() -> None:
194134
ast.Call(
195135
func=ast.Name(id="hypot", ctx=ast.Load()),
196136
args=[],
137+
keywords=[],
197138
),
198139
"hypot",
199140
),
@@ -205,17 +146,58 @@ def test_extract_int_invalid() -> None:
205146
ctx=ast.Load(),
206147
),
207148
args=[],
149+
keywords=[],
208150
),
209151
"hypot",
210152
),
211153
(
212154
ast.Call(
213-
func=ast.Call(func=ast.Name(id="foo", ctx=ast.Load()), args=[]),
155+
func=ast.Call(
156+
func=ast.Name(id="foo", ctx=ast.Load()), args=[], keywords=[]
157+
),
214158
args=[],
159+
keywords=[],
215160
),
216161
None,
217162
),
218163
],
219164
)
220165
def test_extract_function_name_or_none(value: ast.Call, expected: str | None) -> None:
221166
assert ast_utils.extract_function_name_or_none(value) == expected
167+
168+
169+
def test_create_function_def() -> None:
170+
expected_args = ast.arguments(
171+
posonlyargs=[],
172+
args=[ast.arg(arg="x")],
173+
vararg=None,
174+
kwonlyargs=[],
175+
kw_defaults=[],
176+
kwarg=None,
177+
defaults=[],
178+
)
179+
180+
kwargs = {
181+
"name": "test_func",
182+
"args": expected_args,
183+
"body": [ast.Return(value=ast.Name(id="x", ctx=ast.Load()))],
184+
"decorator_list": [],
185+
"returns": None,
186+
"type_comment": None,
187+
"lineno": 1,
188+
"col_offset": 0,
189+
"end_lineno": 2,
190+
"end_col_offset": 0,
191+
}
192+
if sys.version_info.minor >= 12:
193+
kwargs["type_params"] = []
194+
195+
func_def = ast_utils.create_function_def(**kwargs)
196+
assert isinstance(func_def, ast.FunctionDef)
197+
assert func_def.name == "test_func"
198+
199+
assert func_def.args.posonlyargs == expected_args.posonlyargs
200+
assert func_def.args.args == expected_args.args
201+
assert func_def.args.kwonlyargs == expected_args.kwonlyargs
202+
assert func_def.args.kw_defaults == expected_args.kw_defaults
203+
assert func_def.args.defaults == expected_args.defaults

0 commit comments

Comments
 (0)