Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pump Version python to 3.12, 3.13. Allow pip install for python 3.12, 3.13 #210

Merged
merged 16 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
Comment on lines +153 to +163
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add type hints.

) -> 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)
maycuatroi marked this conversation as resolved.
Show resolved Hide resolved
@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
Loading