Repository: tkscode/pyNormalizeNumExp (language: python)

Issue:
複数のPythonバージョンのテストにtoxを利用するように変更



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/upload_python_package.yml b/.github/workflows/upload_python_package.yml
index f95b1b6..9f3b6c8 100644
--- a/.github/workflows/upload_python_package.yml
+++ b/.github/workflows/upload_python_package.yml
@@ -1,4 +1,4 @@
-name: Upload Python Package
+name: Upload Python Package to PyPI
 
 on:
   release:
@@ -7,27 +7,29 @@ on:
 jobs:
   deploy:
     runs-on: ubuntu-latest
+
     steps:
       # リポジトリをチェックアウトする
       # See: https://github.com/actions/checkout
       - name: Checkout
-        uses: actions/checkout@v2
+        uses: actions/checkout@v4
+
       # Python のランタイムをセットアップする
-      # バージョンは `strategy.matrix` に並べたものを指定する
       # See: https://github.com/actions/setup-python
       - name: Set up Python
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v1
         with:
           python-version: '3.11'
+
       # Poetryのインストール
       - name: Install Poetry
         run: |
-          python -m pip install --upgrade pip
-          pip install poetry twine
+          pip install poetry
+
       # パッケージのビルドとPyPIへのアップロード
       - name: Build and publish
         env:
-          TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
-          TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
+          PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
         run: |
-          poetry publish --build --username $TWINE_USERNAME --password $TWINE_PASSWORD
+          poetry config pypi-token.pypi $PYPI_API_TOKEN
+          poetry publish --build
diff --git a/.gitignore b/.gitignore
index d0a8114..7f93772 100644
--- a/.gitignore
+++ b/.gitignore
@@ -138,4 +138,4 @@ dmypy.json
 cython_debug/
 
 # Others
-.python-version
+
diff --git a/.python-version b/.python-version
new file mode 100644
index 0000000..2a4fefb
--- /dev/null
+++ b/.python-version
@@ -0,0 +1,4 @@
+3.11.7
+3.12.1
+3.10.12
+3.9.18
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 1574fe1..dafd13f 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -14,6 +14,7 @@
     "**/.svn": true,
     "**/.hg": true,
     "**/.venv*": true,
+    "**/.tox": true,
     "**/.coverage": true,
     "**/.cov": true,
     "**/.mypy_cache": true,
@@ -30,6 +31,7 @@
     "**/node_modules/*/**": true,
     "**/.hg/store/**": true,
     "**/.venv*/**": true,
+    "**/.tox": true,
     "**/.mypy_cache": true,
     "**/.pytest_cache": true,
     "**/.cov/**": true
diff --git a/poetry.lock b/poetry.lock
index be2deee..de148ad 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -38,6 +38,28 @@ test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)",
 toml = ["tomli (>=1.1.0)"]
 yaml = ["PyYAML"]
 
+[[package]]
+name = "cachetools"
+version = "5.3.2"
+description = "Extensible memoizing collections and decorators"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"},
+    {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"},
+]
+
+[[package]]
+name = "chardet"
+version = "5.2.0"
+description = "Universal encoding detector for Python 3"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
+    {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
+]
+
 [[package]]
 name = "colorama"
 version = "0.4.6"
@@ -116,6 +138,17 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1
 [package.extras]
 toml = ["tomli"]
 
+[[package]]
+name = "distlib"
+version = "0.3.8"
+description = "Distribution utilities"
+optional = false
+python-versions = "*"
+files = [
+    {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
+    {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
+]
+
 [[package]]
 name = "exceptiongroup"
 version = "1.2.0"
@@ -130,6 +163,22 @@ files = [
 [package.extras]
 test = ["pytest (>=6)"]
 
+[[package]]
+name = "filelock"
+version = "3.13.1"
+description = "A platform independent file lock."
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"},
+    {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
+typing = ["typing-extensions (>=4.8)"]
+
 [[package]]
 name = "flake8"
 version = "7.0.0"
@@ -376,6 +425,21 @@ files = [
     {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"},
 ]
 
+[[package]]
+name = "platformdirs"
+version = "4.1.0"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"},
+    {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
+
 [[package]]
 name = "pluggy"
 version = "1.3.0"
@@ -445,6 +509,25 @@ files = [
 plugins = ["importlib-metadata"]
 windows-terminal = ["colorama (>=0.4.6)"]
 
+[[package]]
+name = "pyproject-api"
+version = "1.6.1"
+description = "API to interact with the python pyproject.toml based projects"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "pyproject_api-1.6.1-py3-none-any.whl", hash = "sha256:4c0116d60476b0786c88692cf4e325a9814965e2469c5998b830bba16b183675"},
+    {file = "pyproject_api-1.6.1.tar.gz", hash = "sha256:1817dc018adc0d1ff9ca1ed8c60e1623d5aaca40814b953af14a9cf9a5cae538"},
+]
+
+[package.dependencies]
+packaging = ">=23.1"
+tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
+
+[package.extras]
+docs = ["furo (>=2023.8.19)", "sphinx (<7.2)", "sphinx-autodoc-typehints (>=1.24)"]
+testing = ["covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "setuptools (>=68.1.2)", "wheel (>=0.41.2)"]
+
 [[package]]
 name = "pytest"
 version = "7.4.4"
@@ -599,6 +682,33 @@ files = [
     {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
 ]
 
+[[package]]
+name = "tox"
+version = "4.12.0"
+description = "tox is a generic virtualenv management and test command line tool"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "tox-4.12.0-py3-none-any.whl", hash = "sha256:c94bf5852ba41f3d9f1e3470ccf3390e0b7bdc938095be3cd96dce25ab5062a0"},
+    {file = "tox-4.12.0.tar.gz", hash = "sha256:76adc53a3baff7bde80d6ad7f63235735cfc5bc42e8cb6fccfbf62cb5ffd4d92"},
+]
+
+[package.dependencies]
+cachetools = ">=5.3.2"
+chardet = ">=5.2"
+colorama = ">=0.4.6"
+filelock = ">=3.13.1"
+packaging = ">=23.2"
+platformdirs = ">=4.1"
+pluggy = ">=1.3"
+pyproject-api = ">=1.6.1"
+tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
+virtualenv = ">=20.25"
+
+[package.extras]
+docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-argparse-cli (>=1.11.1)", "sphinx-autodoc-typehints (>=1.25.2)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.11)"]
+testing = ["build[virtualenv] (>=1.0.3)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.2)", "devpi-process (>=1)", "diff-cover (>=8.0.2)", "distlib (>=0.3.8)", "flaky (>=3.7)", "hatch-vcs (>=0.4)", "hatchling (>=1.21)", "psutil (>=5.9.7)", "pytest (>=7.4.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-xdist (>=3.5)", "re-assert (>=1.1)", "time-machine (>=2.13)", "wheel (>=0.42)"]
+
 [[package]]
 name = "typing-extensions"
 version = "4.9.0"
@@ -610,7 +720,27 @@ files = [
     {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
 ]
 
+[[package]]
+name = "virtualenv"
+version = "20.25.0"
+description = "Virtual Python Environment builder"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"},
+    {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"},
+]
+
+[package.dependencies]
+distlib = ">=0.3.7,<1"
+filelock = ">=3.12.2,<4"
+platformdirs = ">=3.9.1,<5"
+
+[package.extras]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
+test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
+
 [metadata]
 lock-version = "2.0"
 python-versions = ">=3.9,<4.0"
-content-hash = "5d4d58bc48c72d92a7c96f6a1c4ce3514a6f1794dec1df2e096d7b5ba23b2fd0"
+content-hash = "058103a113263288478f09c824fc2238c155f2450af03c4f6f5c90d9ef1c8091"
diff --git a/pyproject.toml b/pyproject.toml
index 046875d..9a3d669 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "pynormalizenumexp"
-version = "0.2.0"
+version = "0.2.1"
 description = "NormalizeNumExp for Python"
 authors = ["tkscode"]
 license = "BSD 3-Clause"
@@ -32,6 +32,7 @@ mypy = {version = "1.8.0"}
 [tool.poetry.group.test.dependencies]
 pytest = {version = "7.4.4"}
 pytest-cov = {version = "4.1.0"}
+tox = {version = "4.12.0"}
 
 [build-system]
 requires = ["poetry-core>=1.0.0"]
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..4c5532c
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,12 @@
+[tox]
+env_list =
+    py{39,310,311,312}
+skipsdist = true
+
+[testenv]
+allowlist_externals =
+    poetry
+commands_pre =
+    poetry install --with test
+commands =
+    poetry run pytest


Test patch:
diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml
index d5f634e..850c4a8 100644
--- a/.github/workflows/pytest.yml
+++ b/.github/workflows/pytest.yml
@@ -12,62 +12,69 @@ jobs:
   pytest:
     name: Run tests with pytest
     runs-on: ubuntu-latest
-    # 複数のPythonのバージョンでテストするために `strategy.matrix` を設定する
-    strategy:
-      matrix:
-        python-version: ["3.9", "3.10", "3.11", "3.12"]
+
     steps:
       # リポジトリをチェックアウトする
       # See: https://github.com/actions/checkout
       - name: Checkout
-        uses: actions/checkout@v2
+        uses: actions/checkout@v4
+
       # Pythonのランタイムをセットアップする
       # バージョンは `strategy.matrix` に並べたものを指定する
       # See: https://github.com/actions/setup-python
-      - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v2
+      - name: Set up Python
+        uses: actions/setup-python@v1
         with:
-          python-version: ${{ matrix.python-version }}
+          python-version: '3.11'
+
       # Poetryのインストール
       - name: Install Poetry
         run: |
           pip install poetry
+
       # Poetryを使って必要なPythonパッケージをインストールする
       - name: Install Dependencies
         run: poetry install --with test --no-interaction
+
       # pytestを実行する
       - name: Run Tests
         run: poetry run pytest
+
+      # Codecovへアップロード
       - name: Upload coverage to Codecov
-        # 上記のステップが全て完了した場合にCodecovへアップロード
-        if: ${{ matrix.python-version==3.12 }}
         uses: codecov/codecov-action@v2
         with:
           file: ./coverage.xml
           name: codecov-umbrella
           fail_ci_if_error: true
+
   deploy:
     runs-on: ubuntu-latest
+    needs: pytest
+
     steps:
       # リポジトリをチェックアウトする
       # See: https://github.com/actions/checkout
       - name: Checkout
-        uses: actions/checkout@v2
+        uses: actions/checkout@v4
+
       # Python のランタイムをセットアップする
       # See: https://github.com/actions/setup-python
       - name: Set up Python
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v1
         with:
           python-version: '3.11'
+
       # Poetryのインストール
       - name: Install Poetry
         run: |
           pip install poetry
-      # パッケージのビルドとPyPIへのアップロード
+
+      # パッケージのビルドとTestPyPIへのアップロード
       - name: Build and publish
         env:
           PYPI_API_TOKEN: ${{ secrets.TESTPYPI_API_TOKEN }}
         run: |
           poetry config repositories.testpypi https://test.pypi.org/legacy/
           poetry config pypi-token.testpypi $PYPI_API_TOKEN
-          poetry publish --build --repository testpypi
\ No newline at end of file
+          poetry publish --build --repository testpypi