diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index dfa0275..31aec9e 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -11,10 +11,12 @@ on: jobs: test: runs-on: ${{ matrix.os }} + env: + ACTIONS_STEP_DEBUG: true strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.11"] + os: [ubuntu-latest, macos-latest] + python-version: ["3.9", "3.10", "3.11", "3.12"] permissions: contents: write steps: @@ -35,10 +37,18 @@ jobs: run: | poetry install + + - name: Get Python version for tox + run: | + stripped_py_version=$(echo "${{ matrix.python-version }}" | tr -d '.') + echo "py_version=$stripped_py_version" >> $GITHUB_ENV + id: py_version + - name: Run tests env: SKIP_LOAD_TEST: "true" - run: poetry run tox + run: | + poetry run tox -e py${{ env.py_version }} build: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index c4073fd..f48a6b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +## 0.2.1 + +* Supports tox running multiple Python versions: 3.9, 3.10, 3.11, 3.12 [#15](https://github.com/idjaw/edunet/issues/15) +* CI will now run against 3.9, 3.10, 3.11, 3.12 versions of Python [#15](https://github.com/idjaw/edunet/issues/15) +* REMOVED - Windows in the CI For now. Will address in [#16](https://github.com/idjaw/edunet/issues/16) [#15](https://github.com/idjaw/edunet/issues/15) + ## 0.2.0 * Will now better handle building and deploying in the CI [#7](https://github.com/idjaw/edunet/issues/7) diff --git a/poetry.lock b/poetry.lock index cb9fe9a..ae0e97c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,6 +11,9 @@ files = [ {file = "astroid-3.0.3.tar.gz", hash = "sha256:4148645659b08b70d72460ed1921158027a9e53ae8b7234149b1400eddacbb93"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} + [[package]] name = "attrs" version = "23.2.0" @@ -67,6 +70,8 @@ mypy-extensions = ">=0.4.3" packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -182,6 +187,9 @@ files = [ {file = "coverage-7.4.1.tar.gz", hash = "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04"}, ] +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + [package.extras] toml = ["tomli"] @@ -211,6 +219,20 @@ files = [ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "filelock" version = "3.13.1" @@ -245,17 +267,18 @@ pyflakes = ">=3.2.0,<3.3.0" [[package]] name = "hypothesis" -version = "6.98.2" +version = "6.98.4" description = "A library for property-based testing" optional = false python-versions = ">=3.8" files = [ - {file = "hypothesis-6.98.2-py3-none-any.whl", hash = "sha256:b6b443d2477893f3aacb0cfb9f6ac865f66f063573fd495dd54f565ab29972f6"}, - {file = "hypothesis-6.98.2.tar.gz", hash = "sha256:714910c7545975120beeecf817ff6430f2f7a77d980377575ed04d690e432a09"}, + {file = "hypothesis-6.98.4-py3-none-any.whl", hash = "sha256:8417d1df13e7ba0eb6cba0917e0aa6c8b0b6b35a4e7fb78db6ab84dfbeb8c8fe"}, + {file = "hypothesis-6.98.4.tar.gz", hash = "sha256:785f47ddac183c7ffef9463b5ab7f2e4433ca9b2b1171e52eeb3f8c5b1f09fa2"}, ] [package.dependencies] attrs = ">=22.2.0" +exceptiongroup = {version = ">=1.0.0", markers = "python_version < \"3.11\""} sortedcontainers = ">=2.1.0,<3.0.0" [package.extras] @@ -348,6 +371,7 @@ files = [ [package.dependencies] mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = ">=4.1.0" [package.extras] @@ -455,11 +479,17 @@ files = [ [package.dependencies] astroid = ">=3.0.1,<=3.1.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = {version = ">=0.3.6", markers = "python_version >= \"3.11\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, +] isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] spelling = ["pyenchant (>=3.2,<4.0)"] @@ -478,6 +508,7 @@ files = [ [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)"] @@ -496,26 +527,28 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.23.4" +version = "0.23.5" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.4.tar.gz", hash = "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2"}, - {file = "pytest_asyncio-0.23.4-py3-none-any.whl", hash = "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef"}, + {file = "pytest-asyncio-0.23.5.tar.gz", hash = "sha256:3a048872a9c4ba14c3e90cc1aa20cbc2def7d01c7c8db3777ec281ba9c057675"}, + {file = "pytest_asyncio-0.23.5-py3-none-any.whl", hash = "sha256:4e7093259ba018d58ede7d5315131d21923a60f8a6e9ee266ce1589685c89eac"}, ] [package.dependencies] -pytest = ">=7.0.0,<8" +pytest = ">=7.0.0,<9" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -539,6 +572,22 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +[[package]] +name = "setuptools" +version = "69.1.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "sortedcontainers" version = "2.4.0" @@ -550,6 +599,17 @@ files = [ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + [[package]] name = "tomlkit" version = "0.12.3" @@ -581,6 +641,7 @@ 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] @@ -620,5 +681,5 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.0" -python-versions = "~3.11" -content-hash = "b07dc0fe6ae5005860de183d08925e24b831974fb263b24561cf05d8c2630422" +python-versions = "^3.9" +content-hash = "26342b4e4364b9991c8d6833d0152415ab781c976894c8b3e0fa0dca02a92b58" diff --git a/pyproject.toml b/pyproject.toml index 5c6a54f..f769541 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "edunet" -version = "0.2.0" +version = "0.2.1" description = "Simple Network Simulation For The Funs!" authors = ["Wajdi Al-Hawari "] readme = "README.md" @@ -20,6 +20,7 @@ flake8 = "^7.0.0" pylint = "^3.0.3" tox = "^4.12.1" hypothesis = "^6.92.9" +setuptools = "^69.1.0" [build-system] requires = ["poetry-core"] diff --git a/tests/unit/core/applications/test_application.py b/tests/unit/core/applications/test_application.py index 0786240..7d67b4e 100644 --- a/tests/unit/core/applications/test_application.py +++ b/tests/unit/core/applications/test_application.py @@ -17,9 +17,19 @@ def test_connection_handler_raises_when_methods_not_implemented(): class MyTestApplication(Application): pass - with pytest.raises( - TypeError, - match="Can't instantiate abstract class MyTestApplication " - "with abstract method handle_request", - ): + """ + Please note: Python 3.12 seems to have changed the assertion message being raised so + previous versions are using one set of wording, and Python 3.12 another. + + Tests will match on a substring instead + + E AssertionError: Regex pattern did not match. + E Regex: "Can't instantiate abstract class MyTestApplication with abstract methods + start, stop" + E Input: "Can't instantiate abstract class MyTestApplication without an implementation + for abstract methods 'start', 'stop'" + """ + with pytest.raises(TypeError) as exc: MyTestApplication().handle_request("foo") # type: ignore + + assert "handle_request" in str(exc.value) diff --git a/tests/unit/core/networking/handlers/test_connection_handler.py b/tests/unit/core/networking/handlers/test_connection_handler.py index 61b74b9..99239f2 100644 --- a/tests/unit/core/networking/handlers/test_connection_handler.py +++ b/tests/unit/core/networking/handlers/test_connection_handler.py @@ -17,9 +17,19 @@ def test_connection_handler_raises_when_methods_not_implemented(): class MyTestConnectionHandler(ConnectionHandler): pass - with pytest.raises( - TypeError, - match="Can't instantiate abstract class MyTestConnectionHandler " - "with abstract method handle_connection", - ): + """ + Please note: Python 3.12 seems to have changed the assertion message being raised so + previous versions are using one set of wording, and Python 3.12 another. + + Tests will match on a substring instead + + E AssertionError: Regex pattern did not match. + E Regex: "Can't instantiate abstract class MyTestConnectionHandler with abstract method + handle_connection" + E Input: "Can't instantiate abstract class MyTestConnectionHandler without an implementation + for abstract method 'handle_connection'" + """ + with pytest.raises(TypeError) as exc: MyTestConnectionHandler().handle_connection() + + assert "handle_connection" in str(exc.value) diff --git a/tests/unit/core/networking/listeners/test_listener.py b/tests/unit/core/networking/listeners/test_listener.py index ae07b81..eb8332f 100644 --- a/tests/unit/core/networking/listeners/test_listener.py +++ b/tests/unit/core/networking/listeners/test_listener.py @@ -29,9 +29,19 @@ def test_listener_raises_when_methods_not_implemented(): class MyTestListener(Listener): pass - with pytest.raises( - TypeError, - match="Can't instantiate abstract class MyTestListener with abstract methods" - " accept_connection, handle_request, start, stop", - ): + """ + Please note: Python 3.12 seems to have changed the assertion message being raised so + previous versions are using one set of wording, and Python 3.12 another. + + Tests will match on a substring instead + + E AssertionError: Regex pattern did not match. + E Regex: "Can't instantiate abstract class MyTestListener with abstract methods + start, stop" + E Input: "Can't instantiate abstract class MyTestListener without an implementation + for abstract methods 'handle_request', 'start', 'stop'" + """ + with pytest.raises(TypeError) as exc: MyTestListener().start() + + assert all(s in str(exc.value) for s in ["handle_request", "start", "stop"]) diff --git a/tests/unit/core/networking/listeners/test_tcp_listener.py b/tests/unit/core/networking/listeners/test_tcp_listener.py index df9e6c9..ce73f4b 100644 --- a/tests/unit/core/networking/listeners/test_tcp_listener.py +++ b/tests/unit/core/networking/listeners/test_tcp_listener.py @@ -70,7 +70,7 @@ def test_tcp_listener_stop_success(mock_connection_handler, mock_socket, caplog) tcp_listener.stop() assert tcp_listener.is_listening is False - assert mock_socket_instance.close.called_once + assert mock_socket_instance.close.call_count == 1 assert "Stopping service" in caplog.text assert "All threads terminated. Service has been stopped." in caplog.text diff --git a/tests/unit/core/nodes/test_node.py b/tests/unit/core/nodes/test_node.py index 198c7ad..5dadaee 100644 --- a/tests/unit/core/nodes/test_node.py +++ b/tests/unit/core/nodes/test_node.py @@ -24,9 +24,20 @@ def test_node_raises_when_methods_not_implemented(): class MyNode(Node): pass - with pytest.raises( - TypeError, - match="Can't instantiate abstract class MyNode " - "with abstract methods start, stop", - ): + """ + Please note: Python 3.12 seems to have changed the assertion message being raised so + previous versions are using one set of wording, and Python 3.12 another. + + Tests will match on a substring instead + + E AssertionError: Regex pattern did not match. + E Regex: "Can't instantiate abstract class MyNode with abstract methods + start, stop" + E Input: "Can't instantiate abstract class MyNode without an implementation + for abstract methods 'start', 'stop'" + """ + + with pytest.raises(TypeError) as exc: MyNode(Mock(spec=Listener)).start("foo") # type: ignore + + assert all(s in str(exc.value) for s in ["start", "stop"]) diff --git a/tox.ini b/tox.ini index c15fa41..65fc27d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = formatting, tests +envlist = formatting, tests, py{39,310,311, 312} skipdist = True [testenv] @@ -8,13 +8,22 @@ allowlist_externals = poetry recreate = false commands_pre: poetry install - +setenv = + SKIP_LOAD_TEST={env:SKIP_LOAD_TEST:false} commands = poetry run black --diff --check src/edunet poetry run flake8 --statistics --show-source src/edunet poetry run isort src/edunet --diff poetry run mypy src/edunet --explicit-package-bases --ignore-missing-imports poetry run pylint --disable=C,R,W src/edunet + poetry run pytest -vvvv \ + --cov=src/edunet \ + --cov-report term-missing:skip-covered \ + --cov-report xml:coverage/cobertura.xml \ + --cov-report html:coverage/html \ + --junitxml coverage/junit.xml \ + tests/unit \ + tests/integration [testenv:black] commands =