Skip to content

Commit

Permalink
Pump Version python to 3.12, 3.13. Allow pip install for python 3.12,…
Browse files Browse the repository at this point in the history
… 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]>
  • Loading branch information
maycuatroi and odashi authored Dec 20, 2024
1 parent 678cd0e commit f9c0797
Show file tree
Hide file tree
Showing 17 changed files with 271 additions and 236 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ corresponding $\LaTeX$ expression:

1. *Which Python versions are supported?*

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

2. *Which technique is used?*

Expand Down
16 changes: 8 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ build-backend = "hatchling.build"
name = "latexify-py"
description = "Generates LaTeX math description from Python functions."
readme = "README.md"
requires-python = ">=3.7, <3.12"
requires-python = ">=3.9, <3.14"
license = {text = "Apache Software License 2.0"}
authors = [
{name = "Yusuke Oda", email = "[email protected]"}
Expand All @@ -24,11 +24,11 @@ classifiers = [
"Framework :: IPython",
"Framework :: Jupyter",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Mathematics",
"Topic :: Software Development :: Code Generators",
"Topic :: Text Processing :: Markup :: LaTeX",
Expand All @@ -43,17 +43,17 @@ dynamic = [
[project.optional-dependencies]
dev = [
"build>=0.8",
"black>=22.10",
"flake8>=5.0",
"black>=24.3",
"flake8>=6.0",
"isort>=5.10",
"mypy>=0.991",
"mypy>=1.9",
"notebook>=6.5.1",
"pyproject-flake8>=5.0",
"pyproject-flake8>=6.0",
"pytest>=7.1",
"twine>=4.0",
]
mypy = [
"mypy>=0.991",
"mypy>=1.9",
"pytest>=7.1",
]

Expand Down
1 change: 0 additions & 1 deletion src/latexify/analyzers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from latexify import analyzers, ast_utils, exceptions, test_utils


@test_utils.require_at_least(8)
@pytest.mark.parametrize(
"code,start,stop,step,start_int,stop_int,step_int",
[
Expand Down
114 changes: 75 additions & 39 deletions src/latexify/ast_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,12 @@ def make_constant(value: Any) -> ast.expr:
Raises:
ValueError: Unsupported value type.
"""
if sys.version_info.minor < 8:
if value is None or value is False or value is True:
return ast.NameConstant(value=value)
if value is ...:
return ast.Ellipsis()
if isinstance(value, (int, float, complex)):
return ast.Num(n=value)
if isinstance(value, str):
return ast.Str(s=value)
if isinstance(value, bytes):
return ast.Bytes(s=value)
else:
if (
value is None
or value is ...
or isinstance(value, (bool, int, float, complex, str, bytes))
):
return ast.Constant(value=value)
if (
value is None
or value is ...
or isinstance(value, (bool, int, float, complex, str, bytes))
):
return ast.Constant(value=value)

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

Expand All @@ -87,13 +75,7 @@ def is_constant(node: ast.AST) -> bool:
Returns:
True if the node is a constant, False otherwise.
"""
if sys.version_info.minor < 8:
return isinstance(
node,
(ast.Bytes, ast.Constant, ast.Ellipsis, ast.NameConstant, ast.Num, ast.Str),
)
else:
return isinstance(node, ast.Constant)
return isinstance(node, ast.Constant)


def is_str(node: ast.AST) -> bool:
Expand All @@ -120,20 +102,12 @@ def extract_int_or_none(node: ast.expr) -> int | None:
Returns:
Extracted int value, or None if extraction failed.
"""
if sys.version_info.minor < 8:
if (
isinstance(node, ast.Num)
and isinstance(node.n, int)
and not isinstance(node.n, bool)
):
return node.n
else:
if (
isinstance(node, ast.Constant)
and isinstance(node.value, int)
and not isinstance(node.n, bool)
):
return node.value
if (
isinstance(node, ast.Constant)
and isinstance(node.value, int)
and not isinstance(node.value, bool)
):
return node.value

return None

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

return None


def create_function_def(
name,
args,
body,
decorator_list,
returns=None,
type_comment=None,
type_params=None,
lineno=None,
col_offset=None,
end_lineno=None,
end_col_offset=None,
) -> ast.FunctionDef:
"""Creates a FunctionDef node.
This function generates an `ast.FunctionDef` node, optionally removing
the `type_params` keyword argument for Python versions below 3.12.
Args:
name: Name of the function.
args: Arguments of the function.
body: Body of the function.
decorator_list: List of decorators.
returns: Return type of the function.
type_comment: Type comment of the function.
type_params: Type parameters of the function.
lineno: Line number of the function definition.
col_offset: Column offset of the function definition.
end_lineno: End line number of the function definition.
end_col_offset: End column offset of the function definition.
Returns:
ast.FunctionDef: The generated FunctionDef node.
"""
if sys.version_info.minor < 12:
return ast.FunctionDef(
name=name,
args=args,
body=body,
decorator_list=decorator_list,
returns=returns,
type_comment=type_comment,
lineno=lineno,
col_offset=col_offset,
end_lineno=end_lineno,
end_col_offset=end_col_offset,
) # type: ignore
return ast.FunctionDef(
name=name,
args=args,
body=body,
decorator_list=decorator_list,
returns=returns,
type_comment=type_comment,
type_params=type_params,
lineno=lineno,
col_offset=col_offset,
end_lineno=end_lineno,
end_col_offset=end_col_offset,
) # type: ignore
106 changes: 44 additions & 62 deletions src/latexify/ast_utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import ast
import sys
from typing import Any

import pytest
Expand Down Expand Up @@ -34,29 +35,6 @@ def test_make_attribute() -> None:
)


@test_utils.require_at_most(7)
@pytest.mark.parametrize(
"value,expected",
[
(None, ast.NameConstant(value=None)),
(False, ast.NameConstant(value=False)),
(True, ast.NameConstant(value=True)),
(..., ast.Ellipsis()),
(123, ast.Num(n=123)),
(4.5, ast.Num(n=4.5)),
(6 + 7j, ast.Num(n=6 + 7j)),
("foo", ast.Str(s="foo")),
(b"bar", ast.Bytes(s=b"bar")),
],
)
def test_make_constant_legacy(value: Any, expected: ast.Constant) -> None:
test_utils.assert_ast_equal(
observed=ast_utils.make_constant(value),
expected=expected,
)


@test_utils.require_at_least(8)
@pytest.mark.parametrize(
"value,expected",
[
Expand All @@ -83,25 +61,6 @@ def test_make_constant_invalid() -> None:
ast_utils.make_constant(object())


@test_utils.require_at_most(7)
@pytest.mark.parametrize(
"value,expected",
[
(ast.Bytes(s=b"foo"), True),
(ast.Constant("bar"), True),
(ast.Ellipsis(), True),
(ast.NameConstant(value=None), True),
(ast.Num(n=123), True),
(ast.Str(s="baz"), True),
(ast.Expr(value=ast.Num(456)), False),
(ast.Global(names=["qux"]), False),
],
)
def test_is_constant_legacy(value: ast.AST, expected: bool) -> None:
assert ast_utils.is_constant(value) is expected


@test_utils.require_at_least(8)
@pytest.mark.parametrize(
"value,expected",
[
Expand All @@ -114,25 +73,6 @@ def test_is_constant(value: ast.AST, expected: bool) -> None:
assert ast_utils.is_constant(value) is expected


@test_utils.require_at_most(7)
@pytest.mark.parametrize(
"value,expected",
[
(ast.Bytes(s=b"foo"), False),
(ast.Constant("bar"), True),
(ast.Ellipsis(), False),
(ast.NameConstant(value=None), False),
(ast.Num(n=123), False),
(ast.Str(s="baz"), True),
(ast.Expr(value=ast.Num(456)), False),
(ast.Global(names=["qux"]), False),
],
)
def test_is_str_legacy(value: ast.AST, expected: bool) -> None:
assert ast_utils.is_str(value) is expected


@test_utils.require_at_least(8)
@pytest.mark.parametrize(
"value,expected",
[
Expand Down Expand Up @@ -194,6 +134,7 @@ def test_extract_int_invalid() -> None:
ast.Call(
func=ast.Name(id="hypot", ctx=ast.Load()),
args=[],
keywords=[],
),
"hypot",
),
Expand All @@ -205,17 +146,58 @@ def test_extract_int_invalid() -> None:
ctx=ast.Load(),
),
args=[],
keywords=[],
),
"hypot",
),
(
ast.Call(
func=ast.Call(func=ast.Name(id="foo", ctx=ast.Load()), args=[]),
func=ast.Call(
func=ast.Name(id="foo", ctx=ast.Load()), args=[], keywords=[]
),
args=[],
keywords=[],
),
None,
),
],
)
def test_extract_function_name_or_none(value: ast.Call, expected: str | None) -> None:
assert ast_utils.extract_function_name_or_none(value) == expected


def test_create_function_def() -> None:
expected_args = ast.arguments(
posonlyargs=[],
args=[ast.arg(arg="x")],
vararg=None,
kwonlyargs=[],
kw_defaults=[],
kwarg=None,
defaults=[],
)

kwargs = {
"name": "test_func",
"args": expected_args,
"body": [ast.Return(value=ast.Name(id="x", ctx=ast.Load()))],
"decorator_list": [],
"returns": None,
"type_comment": None,
"lineno": 1,
"col_offset": 0,
"end_lineno": 2,
"end_col_offset": 0,
}
if sys.version_info.minor >= 12:
kwargs["type_params"] = []

func_def = ast_utils.create_function_def(**kwargs)
assert isinstance(func_def, ast.FunctionDef)
assert func_def.name == "test_func"

assert func_def.args.posonlyargs == expected_args.posonlyargs
assert func_def.args.args == expected_args.args
assert func_def.args.kwonlyargs == expected_args.kwonlyargs
assert func_def.args.kw_defaults == expected_args.kw_defaults
assert func_def.args.defaults == expected_args.defaults
Loading

0 comments on commit f9c0797

Please sign in to comment.