diff --git a/.devcontainer/toxic/devcontainer.json b/.devcontainer/toxic/devcontainer.json index 6766c6f5..db46fc3c 100644 --- a/.devcontainer/toxic/devcontainer.json +++ b/.devcontainer/toxic/devcontainer.json @@ -20,5 +20,5 @@ ] } }, - "postCreateCommand": "git submodule update --init --recursive && tox -e local" + "postCreateCommand": "git submodule update --init --recursive && nox -s local" } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2d9a39c8..583f863d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,21 +13,23 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + - name: setup nox + run: pip install nox - name: version-check # Fails the release if the release-tag doesn't match the Nunavut version at that tag. run: | python3 ./src/nunavut/_version.py -v --fail-on-mismatch --tag=${{ github.ref }} - name: lint - run: tox -e lint + run: nox -s lint - name: test-nnvg - run: tox -e py311-nnvg + run: nox -s nnvg-3.11 - name: test-doctest - run: tox -e py311-doctest,py311-rstdoctest + run: nox -s doctest-3.11 rstdoctest-3.11 - name: test-pytest - run: tox -e py311-test + run: nox -s test-3.11 - name: package - run: tox -e package + run: nox -s package - name: upload run: | pip3 install twine - twine upload -u __token__ -p ${{ secrets.PYPI_PASSWORD }} .tox/package/dist/* + twine upload -u __token__ -p ${{ secrets.PYPI_PASSWORD }} .nox/package/tmp/dist/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6a45ee3c..ecd9a17e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,33 +18,35 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + - name: setup nox + run: pip install nox - name: lint - run: tox -e lint + run: nox -s lint - name: test-nnvg - run: tox -e py311-nnvg + run: nox -s nnvg-3.11 - name: test-doctest - run: tox -e py311-doctest,py311-rstdoctest + run: nox -s doctest-3.11 rstdoctest-3.11 - name: test-pytest - run: tox -e py311-test + run: nox -s test-3.11 - name: test-report - run: tox -e report + run: nox -s report - name: package - run: tox -e package + run: nox -s package - name: upload-coverage-reports uses: actions/upload-artifact@v4 with: name: coverage-reports - path: .tox/report/tmp/* + path: .nox/report/tmp/* - name: upload-xunit-results uses: actions/upload-artifact@v4 with: name: xunit-results - path: .tox/py311-test/tmp/xunit-result.xml + path: .nox/test-3-11/tmp/xunit-result.xml - name: upload-package uses: actions/upload-artifact@v4 with: name: pypi-package - path: .tox/package/dist/* + path: .nox/package/tmp/dist/* sonar: runs-on: ubuntu-latest @@ -58,18 +60,18 @@ jobs: uses: actions/download-artifact@v4 with: name: coverage-reports - path: .tox/report/tmp/ + path: .nox/report/tmp/ - name: download-xunit-results uses: actions/download-artifact@v4 with: name: xunit-results - path: .tox/py311-test/tmp/ + path: .nox/test-3-11/tmp/ - name: set-environment run: | echo NUNAVUT_MAJOR_MINOR_VERSION=$(./src/nunavut/_version.py --major-minor-only) >> $GITHUB_ENV - - name: verify tox artifacts + - name: verify nox artifacts run: ls -R - working-directory: .tox + working-directory: .nox - name: report-release if: ${{ github.event_name != 'pull_request' }} uses: SonarSource/sonarqube-scan-action@v4.2.1 @@ -82,8 +84,8 @@ jobs: -Dsonar.buildString=${{ env.GITHUB_RUN_ID }} -Dsonar.projectVersion=${{ env.NUNAVUT_MAJOR_MINOR_VERSION }} -Dsonar.python.version=python3.11 - -Dsonar.python.coverage.reportPaths=.tox/report/tmp/coverage.xml - -Dsonar.python.xunit.reportPath=.tox/py311-test/tmp/xunit-result.xml + -Dsonar.python.coverage.reportPaths=.nox/report/tmp/coverage.xml + -Dsonar.python.xunit.reportPath=.nox/test-3-11/tmp/xunit-result.xml - name: report-pr if: ${{ github.event_name == 'pull_request' }} uses: SonarSource/sonarqube-scan-action@v4.2.1 @@ -96,8 +98,8 @@ jobs: -Dsonar.buildString=${{ env.GITHUB_RUN_ID }} -Dsonar.projectVersion=${{ env.NUNAVUT_MAJOR_MINOR_VERSION }} -Dsonar.python.version=python3.11 - -Dsonar.python.coverage.reportPaths=.tox/report/tmp/coverage.xml - -Dsonar.python.xunit.reportPath=.tox/py311-test/tmp/xunit-result.xml + -Dsonar.python.coverage.reportPaths=.nox/report/tmp/coverage.xml + -Dsonar.python.xunit.reportPath=.nox/test-3-11/tmp/xunit-result.xml compat-test-python3-windows-and-mac: strategy: @@ -114,10 +116,10 @@ jobs: uses: actions/setup-python@v5 with: python-version: 3.${{ matrix.python3-version }} - - name: setup tox - run: pip3 install tox + - name: setup nox + run: pip3 install nox - name: python3.${{ matrix.python3-version }} test - run: tox -e py3${{ matrix.python3-version }}-nnvg,py3${{ matrix.python3-version }}-test + run: nox -s nnvg-3.${{ matrix.python3-version }} test-3.${{ matrix.python3-version }} compat-test-python3-ubuntu: strategy: @@ -130,8 +132,10 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + - name: setup nox + run: pip install nox - name: python3.${{ matrix.python3-version }} test - run: tox -e py3${{ matrix.python3-version }}-nnvg,py3${{ matrix.python3-version }}-test + run: nox -s nnvg-3.${{ matrix.python3-version }} test-3.${{ matrix.python3-version }} language-verification-c-cpp: runs-on: ubuntu-latest diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..ac845097 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,14 @@ +[MAIN] +ignore-paths = .*/(jinja2|markupsafe)/.* +source-roots = src + +[FORMAT] +max-line-length = 120 + +[DESIGN] +max-args = 8 +max-attributes = 12 +min-public-methods = 0 + +[MESSAGES CONTROL] +disable = no-else-return,invalid-name,too-many-positional-arguments diff --git a/.vscode/settings.json b/.vscode/settings.json index 8455ebed..03c8f913 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "python.testing.pytestEnabled": true, "python.testing.pytestArgs": ["-vv"], "pylint.args": [ - "--rcfile=${workspaceFolder}/tox.ini" + "--rcfile=${workspaceFolder}/.pylintrc" ], "isort.args": [ "--line-length=120" @@ -15,7 +15,7 @@ ], "mypy-type-checker.args": [ "--config-file", - "${workspaceFolder}/tox.ini" + "${workspaceFolder}/pyproject.toml" ], "mypy-type-checker.importStrategy": "fromEnvironment", "flake8.args": [ @@ -142,5 +142,9 @@ "sonarlint.connectedMode.project": { "connectionId": "opencyphal", "projectKey": "OpenCyphal_nunavut" - } + }, + "python-envs.workspaceSearchPaths": [ + "./**/.venv", + "./.nox/local" + ] } diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 6fc5c2aa..108534b2 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -28,21 +28,22 @@ will kickoff and do the rest for you. Tools ************************************************ -tox devenv -e local +nox -s local ================================================ -I highly recommend using the local tox environment when doing python development. It'll save you hours +I highly recommend using the local nox session when doing python development. It'll save you hours of lost productivity the first time it keeps you from pulling in an unexpected dependency from your -global python environment. You can install tox from brew on osx or apt-get on GNU/Linux. I'd +global python environment. You can install nox from brew on osx or pip on any platform. I'd recommend the following environment for vscode:: git submodule update --init --recursive - tox devenv -e local - source venv/bin/activate + pip install nox + nox -s local + source .nox/local/bin/activate On Windows that last line is instead:: - ./venv/Scripts/activate + .\.nox\local\Scripts\activate cmake ================================================ @@ -58,15 +59,16 @@ To use vscode you'll need: 1. vscode 2. install vscode command line (`Shell Command: Install`) -3. tox +3. nox 4. cmake (and an available GCC or Clang toolchain, or Docker to use our toolchain-as-container) Do:: cd path/to/nunavut git submodule update --init --recursive - tox devenv -e local - source venv/bin/activate + pip install nox + nox -s local + source .nox/local/bin/activate code . Then install recommended extensions. @@ -75,15 +77,15 @@ Then install recommended extensions. Running The Tests ************************************************ -To run the full suite of `tox`_ tests locally you'll need docker. Once you have docker installed +To run the full suite of `nox`_ tests locally you'll need docker. Once you have docker installed and running do:: git submodule update --init --recursive docker pull ghcr.io/opencyphal/toxic:tx22.4.3 - docker run --rm -v $PWD:/repo ghcr.io/opencyphal/toxic:tx22.4.3 tox + docker run --rm -v $PWD:/repo ghcr.io/opencyphal/toxic:tx22.4.3 /bin/sh -c "pip install nox && nox" To run a limited suite using only locally available interpreters directly on your host machine, -skip the docker invocations and use ``tox run -s``. +skip the docker invocations and use ``nox``. To run the language verification build you'll need to use a different docker container:: @@ -210,13 +212,13 @@ Building The Docs ************************************************ We rely on `read the docs`_ to build our documentation from github but we also verify this build -as part of our tox build. This means you can view a local copy after completing a full, successful +as part of our nox build. This means you can view a local copy after completing a full, successful test run (See `Running The Tests`_) or do -:code:`docker run --rm -t -v $PWD:/repo ghcr.io/opencyphal/toxic:tx22.4.3 /bin/sh -c "tox run -e docs"` to build -the docs target. You can open the index.html under ``.tox_{host platform}/docs/tmp/index.html`` or run a local +:code:`docker run --rm -t -v $PWD:/repo ghcr.io/opencyphal/toxic:tx22.4.3 /bin/sh -c "pip install nox && nox -s docs"` to build +the docs target. You can open the index.html under ``.nox/docs/tmp/index.html`` or run a local web-server:: - python3 -m http.server --directory .tox_{host platform}/docs/tmp & + python3 -m http.server --directory .nox/docs/tmp & open http://localhost:8000/docs/index.html Of course, you can just use `Visual Studio Code`_ to build and preview the docs using @@ -227,16 +229,16 @@ Of course, you can just use `Visual Studio Code`_ to build and preview the docs Coverage and Linting Reports ************************************************ -We publish the results of our coverage data to `sonarcloud`_ and the tox build will fail for any mypy -or black errors but you can view additional reports locally under the :code:`.tox_{host platform}` dir. +We publish the results of our coverage data to `sonarcloud`_ and the nox build will fail for any mypy +or black errors but you can view additional reports locally under the :code:`.nox` dir. Coverage ================================================ -We generate a local html coverage report. You can open the index.html under .tox_{host platform}/report/tmp +We generate a local html coverage report. You can open the index.html under .nox/report/tmp or run a local web-server:: - python -m http.server --directory .tox_{host platform}/report/tmp & + python -m http.server --directory .nox/report/tmp & open http://localhost:8000/index.html Mypy @@ -244,8 +246,8 @@ Mypy At the end of the mypy run we generate the following summaries: -- .tox_{host platform}/mypy/tmp/mypy-report-lib/index.txt -- .tox_{host platform}/mypy/tmp/mypy-report-script/index.txt +- .nox/lint/tmp/mypy-report-lib/index.txt +- .nox/lint/tmp/mypy-report-script/index.txt ************************************************ Nunavut Verification Suite @@ -326,7 +328,7 @@ three variables you can set in your environment or pass into cmake if using cmak All other options set when generating code are provided by setting ``NUNAVUT_EXTRA_GENERATOR_ARGS`` in your environment. .. _`read the docs`: https://readthedocs.org/ -.. _`tox`: https://tox.readthedocs.io/en/latest/ +.. _`nox`: https://nox.thea.codes/en/stable/ .. _`sonarcloud`: https://sonarcloud.io/dashboard?id=OpenCyphal_nunavut .. _`OpenCyphal website`: http://opencyphal.org .. _`OpenCyphal forum`: https://forum.opencyphal.org diff --git a/README.rst b/README.rst index ae37f72c..e3afa5fb 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ Nunavut: DSDL transpiler ################################################ +--------------------------------+-----------------------------------+ -| tox build (main) | |badge_build|_ | +| nox build (main) | |badge_build|_ | +--------------------------------+-----------------------------------+ | static analysis | |badge_analysis|_ |badge_issues|_ | +--------------------------------+-----------------------------------+ @@ -222,9 +222,9 @@ Nunavut is part of the OpenCyphal project: :alt: Documentation Status .. _badge_docs: https://nunavut.readthedocs.io/en/latest/?badge=latest -.. |badge_build| image:: https://github.com/OpenCyphal/nunavut/actions/workflows/test_and_release.yml/badge.svg +.. |badge_build| image:: https://github.com/OpenCyphal/nunavut/actions/workflows/test.yml/badge.svg :alt: Build status -.. _badge_build: https://github.com/OpenCyphal/nunavut/actions/workflows/test_and_release.yml +.. _badge_build: https://github.com/OpenCyphal/nunavut/actions/workflows/test.yml .. |badge_pypi_support| image:: https://img.shields.io/pypi/pyversions/nunavut.svg :alt: Supported Python Versions diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000..28f4f361 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,297 @@ +# +# Copyright (C) OpenCyphal Development Team +# Copyright Amazon.com Inc. or its affiliates. +# SPDX-License-Identifier: MIT +# +""" +Nox session definitions for nunavut. + +The standard version to develop against is 3.11. Minimum supported version is 3.10. +""" + +import glob +import os +from pathlib import Path + +import nox + +# +---------------------------------------------------------------------------+ +# | CONFIGURATION +# +---------------------------------------------------------------------------+ + +PYTHON_VERSIONS = ["3.10", "3.11", "3.12", "3.13"] +DEFAULT_PYTHON = "3.11" + +BASE_DEPS = [ + "Sybil", + "pytest", + "pytest-timeout", + "pytest-cov", + "pytest-profiling", + "coverage", + "types-PyYAML", + "pyyaml", +] + +DEV_DEPS = [ + *BASE_DEPS, + "autopep8", + "rope", + "isort", + "nox", + "jsonschema", +] + +LINT_DEPS = [ + *DEV_DEPS, + "black", + "pylint", + "doc8", + "Pygments", + "mypy", + "lxml", +] + +nox.options.sessions = [ + "lint", + f"nnvg-{DEFAULT_PYTHON}", + f"doctest-{DEFAULT_PYTHON}", + f"rstdoctest-{DEFAULT_PYTHON}", + f"test-{DEFAULT_PYTHON}", + "report", +] + + +# +---------------------------------------------------------------------------+ +# | HELPERS +# +---------------------------------------------------------------------------+ + + +def _project_root() -> Path: + """Return the absolute path to the project root.""" + return Path(__file__).parent.resolve() + + +def _forward_github_env(session: nox.Session) -> None: + """Forward GITHUB_* environment variables into the session.""" + for key, value in os.environ.items(): + if key == "GITHUB" or key.startswith("GITHUB_"): + session.env[key] = value + + +# +---------------------------------------------------------------------------+ +# | SESSIONS +# +---------------------------------------------------------------------------+ + + +@nox.session(python=PYTHON_VERSIONS) +def test(session: nox.Session) -> None: + """Run the test suite with coverage.""" + session.install("-e", ".") + session.install(*BASE_DEPS) + session.env["PYTHONDONTWRITEBYTECODE"] = "1" + _forward_github_env(session) + tmpdir = session.create_tmp() + session.run( + "coverage", + "run", + "-m", + "pytest", + *session.posargs, + f"--basetemp={tmpdir}", + "-p", + "no:cacheprovider", + f"--junit-xml={tmpdir}/xunit-result.xml", + f"--rootdir={_project_root()}", + str(_project_root() / "test"), + ) + session.run("coverage", "combine", "--append") + + +@nox.session(python=PYTHON_VERSIONS) +def nnvg(session: nox.Session) -> None: + """Run nnvg code generation with coverage.""" + session.install("-e", ".") + session.install(*BASE_DEPS) + session.env["PYTHONDONTWRITEBYTECODE"] = "1" + _forward_github_env(session) + tmpdir = session.create_tmp() + session.run( + "coverage", + "run", + "-m", + "nunavut", + "-O", + tmpdir, + "--target-language", + "cpp", + "--experimental-languages", + "--language-standard", + "c++17-pmr", + "-v", + str(_project_root() / "submodules" / "public_regulated_data_types" / "uavcan"), + ) + session.run("coverage", "combine", "--append") + + +@nox.session(python=PYTHON_VERSIONS) +def doctest(session: nox.Session) -> None: + """Run doctests in source code with coverage.""" + session.install("-e", ".") + session.install(*BASE_DEPS) + session.env["PYTHONDONTWRITEBYTECODE"] = "1" + _forward_github_env(session) + tmpdir = session.create_tmp() + session.run( + "coverage", + "run", + "-m", + "pytest", + *session.posargs, + f"--basetemp={tmpdir}", + "-p", + "no:cacheprovider", + "--ignore-glob=*.bak", + f"--rootdir={_project_root()}", + str(_project_root() / "src"), + ) + session.run("coverage", "combine", "--append") + + +@nox.session(python=PYTHON_VERSIONS) +def rstdoctest(session: nox.Session) -> None: + """Run doctests in RST documentation.""" + session.install("-e", ".") + session.install(*BASE_DEPS) + session.env["PYTHONDONTWRITEBYTECODE"] = "1" + _forward_github_env(session) + tmpdir = session.create_tmp() + session.run( + "pytest", + *session.posargs, + f"--basetemp={tmpdir}", + "-p", + "no:cacheprovider", + f"--rootdir={_project_root()}", + str(_project_root() / "docs"), + ) + + +@nox.session(python=DEFAULT_PYTHON) +def lint(session: nox.Session) -> None: + """Run linters (pylint, black, doc8, mypy).""" + session.install("-e", ".") + session.install(*LINT_DEPS) + tmpdir = session.create_tmp() + root = _project_root() + session.run( + "pylint", + "--reports=y", + f"--rcfile={root / '.pylintrc'}", + f"--output={tmpdir}/pylint.txt", + "--output-format=json2", + "--clear-cache-post-run=y", + "--confidence=HIGH", + str(root / "src" / "nunavut"), + ) + session.run( + "black", + "--check", + "--line-length", + "120", + "--force-exclude", + r"(/jinja2/|/markupsafe/)", + str(root / "src"), + ) + session.run( + "doc8", + "--ignore-path", + str(root / "docs" / "cmake" / "build"), + "--ignore-path", + str(root / "docs" / "cmake" / "external"), + str(root / "docs"), + ) + session.run( + "mypy", + "-p", + "nunavut", + f"--cache-dir={tmpdir}", + f"--txt-report={tmpdir}/mypy-report-lib", + f"--config-file={root / 'pyproject.toml'}", + ) + + +@nox.session(python=DEFAULT_PYTHON) +def docs(session: nox.Session) -> None: + """Build Sphinx documentation.""" + session.install("-e", ".") + session.install("-r", "requirements.txt") + session.install("sphinx") + tmpdir = session.create_tmp() + session.run("sphinx-build", "-W", "-b", "html", str(_project_root()), tmpdir) + + +@nox.session(python=DEFAULT_PYTHON) +def report(session: nox.Session) -> None: + """Generate coverage reports (HTML and XML).""" + session.install("coverage") + tmpdir = session.create_tmp() + session.run("coverage", "combine", "--append", success_codes=[0, 1]) + session.run("coverage", "html", "-d", tmpdir) + session.run("coverage", "xml", "-o", f"{tmpdir}/coverage.xml") + + +@nox.session(python=DEFAULT_PYTHON) +def package(session: nox.Session) -> None: + """Build and check the distribution package.""" + session.install("build", "twine", "setuptools") + session.install("-e", ".") + tmpdir = session.create_tmp() + dist_dir = str(Path(tmpdir) / "dist") + session.run("python", "version_check_pydsdl.py", "-vv") + session.run( + "python", + "-m", + "build", + "-o", + dist_dir, + "--sdist", + "--wheel", + f"--config-setting=--build-number={os.environ.get('GITHUB_RUN_ID', '0')}", + ) + dist_files = glob.glob(f"{dist_dir}/*") + session.run("twine", "check", *dist_files) + + +@nox.session(python=DEFAULT_PYTHON) +def format(session: nox.Session) -> None: + """Run code formatters (isort, black).""" + session.install("-e", ".") + session.install(*DEV_DEPS, "black") + root = _project_root() + session.run( + "isort", + "--skip-glob", + "*/jinja2/*", + "--skip-glob", + "*/markupsafe/*", + str(root / "src" / "nunavut"), + ) + session.run( + "black", + "--line-length", + "120", + "--force-exclude", + r"(/jinja2/|/markupsafe/)", + str(root / "src"), + ) + + +@nox.session(python=DEFAULT_PYTHON) +def local(session: nox.Session) -> None: + """Set up a local development environment with all dependencies.""" + session.install("-e", ".") + session.install(*LINT_DEPS) + session.install("-r", "requirements.txt") + session.install("sphinx") + session.run("python", "--version") diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..91bf0b00 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,165 @@ +# +# Copyright (C) OpenCyphal Development Team +# Copyright Amazon.com Inc. or its affiliates. +# SPDX-License-Identifier: MIT +# + +[build-system] +requires = ["setuptools >= 68.0", "wheel"] +build-backend = "setuptools.build_meta" + +# +---------------------------------------------------------------------------+ +# | PROJECT METADATA (PEP 621) +# +---------------------------------------------------------------------------+ + +[project] +name = "nunavut" +dynamic = ["version"] +description = "Generate code from DSDL using Jinja2 templates." +readme = {file = "README.rst", content-type = "text/x-rst"} +license = "MIT" +license-files = ["LICENSE.rst"] +requires-python = ">= 3.10" +keywords = [ + "uavcan", "dsdl", "can", "can-bus", "ethernet", "udp", + "codegen", "cyphal", "opencyphal", +] +authors = [ + {name = "OpenCyphal Development Team", email = "maintainers@opencyphal.org"}, +] +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Scientific/Engineering", + "Topic :: Software Development :: Embedded Systems", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Code Generators", + "Topic :: Software Development :: Build Tools", + "Topic :: System :: Distributed Computing", + "Topic :: System :: Networking", + "Typing :: Typed", +] +dependencies = [ + "pydsdl >= 1.24.3", +] + +[project.optional-dependencies] +shell = ["argcomplete"] +config = ["pyyaml"] + +[project.urls] +Homepage = "https://opencyphal.org" +Repository = "https://github.com/OpenCyphal/nunavut" + +[project.scripts] +nnvg = "nunavut.cli.runners:main" + +# +---------------------------------------------------------------------------+ +# | SETUPTOOLS CONFIGURATION +# +---------------------------------------------------------------------------+ + +[tool.setuptools.dynamic] +version = {attr = "nunavut._version.__version__"} + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +"*" = ["*.j2", "**/*.css", "**/*.js", "*.ini", "*.json", "*.hpp", "*.h"] +nunavut = ["py.typed"] + +# +---------------------------------------------------------------------------+ +# | TOOL CONFIGURATION +# +---------------------------------------------------------------------------+ + +[tool.pytest.ini_options] +log_file = "pytest.log" +log_level = "DEBUG" +log_cli = true +log_cli_level = "WARNING" +norecursedirs = ["submodules", ".*", "build*", "verification", ".nox"] +addopts = "-p no:doctest" + +[tool.coverage.run] +data_file = "build/coverage-py/.coverage" +branch = true +parallel = true +relative_files = true +include = [ + "src/nunavut/*", + ".nox/*/lib/*/site-packages/nunavut/*", +] +omit = [ + "*/jinja2/*", + "*/markupsafe/*", + "*/setup.py", + "*/conf.py", + "*/public_regulated_data_types/*", +] + +[tool.setuptools] + zip-safe = false + +[tool.coverage.paths] +source = [ + "src", + ".nox/*/lib/*/site-packages", + ".nox/*/bin", +] + +[tool.coverage.report] +exclude_also = [ + "pragma: no cover", + "def __repr__", + "raise AssertionError", + "raise NotImplementedError", + "assert False", + "if False:", + "if __name__ == .__main__.:", +] +omit = ["*.j2"] + +[tool.doc8] +max-line-length = 120 +verbose = 1 + +[tool.mypy] +warn_return_any = true +warn_unused_configs = true +disallow_untyped_defs = true +check_untyped_defs = true +no_implicit_optional = true +warn_redundant_casts = true +warn_unused_ignores = true +show_error_context = true +mypy_path = "src" +exclude = "(jinja2|markupsafe)" +python_version = "3.10" + +[[tool.mypy.overrides]] +module = "pydsdl" +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "nunavut.jinja.jinja2.*" +follow_imports = "skip" + +[[tool.mypy.overrides]] +module = "pytest.*" +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "sybil.*" +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "setuptools.*" +ignore_missing_imports = true diff --git a/requirements.txt b/requirements.txt index 9962eb9b..d7e52765 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -# This file provided for readthedocs.io only. Use tox.ini for all dependencies. +# This file provided for readthedocs.io only. Use noxfile.py for all dependencies. . furo diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 59327c3b..00000000 --- a/setup.cfg +++ /dev/null @@ -1,54 +0,0 @@ -[metadata] -name = nunavut -author = OpenCyphal Development Team -author_email = maintainers@opencyphal.org -url = https://opencyphal.org -description = Generate code from DSDL using Jinja2 templates. -long_description = file: README.rst -long_description_content_type = text/x-rst -license = MIT -license_files = LICENSE.rst -keywords = uavcan, dsdl, can, can-bus, ethernet, udp, codegen, cyphal, opencyphal -classifiers = - Development Status :: 3 - Alpha - Environment :: Console - Intended Audience :: Developers - License :: OSI Approved :: MIT License - Programming Language :: Python - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: 3.12 - Programming Language :: Python :: 3.13 - Programming Language :: Python :: 3 :: Only - Topic :: Scientific/Engineering - Topic :: Software Development :: Embedded Systems - Topic :: Software Development :: Libraries - Topic :: Software Development :: Code Generators - Topic :: Software Development :: Build Tools - Topic :: System :: Distributed Computing - Topic :: System :: Networking - Typing :: Typed - -[options] -package_dir= - =src -packages=find: -package_data={"nunavut": ["py.typed"]} - -[options.extras_require] -shell = - argcomplete -config = - pyyaml - -zip_safe = False - -python_requires >= 3.10 - -[options.entry_points] -console_scripts = - nnvg = nunavut.cli.runners:main - -[options.packages.find] -where=src diff --git a/setup.py b/setup.py deleted file mode 100755 index fdfc8b5f..00000000 --- a/setup.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2018 OpenCyphal Development Team -# This software is distributed under the terms of the MIT License. -# - -import sys -from typing import Dict -import re - -import setuptools - -if int(setuptools.__version__.split(".")[0]) < 30: - print( - "A newer version of setuptools is required. The current version does not support declarative config.", - file=sys.stderr, - ) - sys.exit(1) - -version = {} # type: Dict -version_file_path = "src/nunavut/_version.py" - -with open(version_file_path, encoding="utf-8") as fp: - exec(fp.read(), version) # pylint: disable=W0122 - - -specifier_pattern = r"(~=|==|!=|<=|>=|<|>|===)\s*([\w.-]+)" -match = re.search(specifier_pattern, version['__pydsdl_version__']) - -if not match: - raise ValueError(f"Unknown version format for __pydsdl_version__ in {version_file_path}") - -pydsdl_version_specifier = f"pydsdl {match.group(1)} {match.group(2)}" -package_data = {"": ["*.j2", "**/*.css", "**/*.js", "*.ini", "*.json", "*.hpp", "*.h"]} - -setuptools.setup( - version=version["__version__"], - package_data=package_data, - install_requires=[pydsdl_version_specifier], -) diff --git a/src/nunavut/_version.py b/src/nunavut/_version.py index b8585a48..d64a9186 100644 --- a/src/nunavut/_version.py +++ b/src/nunavut/_version.py @@ -18,7 +18,7 @@ "Development Team ." ) __email__ = "maintainers@opencyphal.org" -__pydsdl_version__ = ">= 1.22.2" +__pydsdl_version__ = ">= 1.24.3" def _parse_version_string(tag: str, pattern: str, major_minor_only: bool) -> list: # pragma: no cover diff --git a/submodules/pydsdl b/submodules/pydsdl index 00445d4f..2229ca52 160000 --- a/submodules/pydsdl +++ b/submodules/pydsdl @@ -1 +1 @@ -Subproject commit 00445d4fcec16cf5270c2e1b9b33e195e1047005 +Subproject commit 2229ca522f2aa9c6de17999d9ee3c4a6ef14ca06 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 94035f25..00000000 --- a/tox.ini +++ /dev/null @@ -1,251 +0,0 @@ -# -# The standard version to develop against is 3.11. Minimum supported version is 3.10. -# -[tox] -envlist = {py310,py311,py312,py313}-{test,nnvg,doctest,rstdoctest},lint,report,docs - -[base] -deps = - Sybil - pytest - pytest-timeout - pytest-cov - pytest-profiling - coverage - types-PyYAML - pyyaml - -[dev] -deps = - {[base]deps} - autopep8 - rope - isort - nox - jsonschema - -# +---------------------------------------------------------------------------+ -# | CONFIGURATION -# +---------------------------------------------------------------------------+ - - -[pylint] -max-line-length = 120 -max-args = 8 -max-attributes = 12 -ignore-paths = .*/(jinja2|markupsafe)/.* -min-public-methods = 0 -source-roots = src -disable = no-else-return,invalid-name,too-many-positional-arguments - - -[pytest] -log_file = pytest.log -log_level = DEBUG -log_cli = true -log_cli_level = WARNING -norecursedirs = submodules .* build* verification {toxworkdir} -addopts = -p no:doctest - -[coverage:run] -data_file = build/coverage-py/.coverage -branch=True -parallel=True -relative_files = True -include = - src/nunavut/* - {toxworkdir}/*/site-packages/nunavut/* - -omit = - */jinja2/* - */markupsafe/* - */setup.py - */conf.py - */public_regulated_data_types/* - - -[coverage:paths] -source = - src - {toxworkdir}/*/site-packages - {toxworkdir}/*/bin - - -[coverage:report] -exclude_also = - pragma: no cover - def __repr__ - raise AssertionError - raise NotImplementedError - assert False - if False: - if __name__ == .__main__.: -omit = *.j2 - -[doc8] -max-line-length = 120 -verbose = 1 - - -[mypy] -# Python version is not specified to allow checking against different versions -warn_return_any = True -warn_unused_configs = True -disallow_untyped_defs = True -check_untyped_defs = True -no_implicit_optional = True -warn_redundant_casts = True -warn_unused_ignores = True -show_error_context = True -mypy_path = src -exclude = (jinja2|markupsafe) -python_version = 3.10 - -[mypy-pydsdl] -ignore_missing_imports = True - -[mypy-nunavut.jinja.jinja2.*] -follow_imports = skip - -[mypy-pytest.*] -ignore_missing_imports = True - -[mypy-sybil.*] -ignore_missing_imports = True - -[mypy-setuptools.*] -ignore_missing_imports = True - -# +---------------------------------------------------------------------------+ -# | TOX ENVIRONMENTS -# +---------------------------------------------------------------------------+ - - -[testenv] -usedevelop = true -setenv = - PYTHONDONTWRITEBYTECODE=1 - -passenv = - GITHUB - GITHUB_* - -deps = - test,nnvg,doctest,rstdoctest: {[base]deps} - -allowlist_externals = - coverage - -commands = - - nnvg: coverage run \ - nnvg: -m nunavut \ - nnvg: -O {envtmpdir} \ - nnvg: --target-language cpp \ - nnvg: --experimental-languages \ - nnvg: --language-standard c++17-pmr \ - nnvg: -v \ - nnvg: {toxinidir}/submodules/public_regulated_data_types/uavcan - nnvg: coverage combine --append - - test: coverage run \ - test: -m pytest {posargs} --basetemp={envtmpdir} -p "no:cacheprovider" \ - test: --junit-xml={envtmpdir}/xunit-result.xml \ - test: --rootdir={toxinidir} \ - test: {toxinidir}/test - test: coverage combine --append - - doctest: coverage run \ - doctest: -m pytest {posargs} --basetemp={envtmpdir} -p "no:cacheprovider" \ - doctest: --rootdir={toxinidir} \ - doctest: {toxinidir}/src - doctest: coverage combine --append - - rstdoctest: pytest {posargs} --basetemp={envtmpdir} -p "no:cacheprovider" \ - rstdoctest: --rootdir={toxinidir} \ - rstdoctest: {toxinidir}/docs - - -[testenv:docs] -deps = - -rrequirements.txt - sphinx -commands = - sphinx-build -W -b html {toxinidir} {envtmpdir} - - -[testenv:report] -deps = coverage -skip_install = true -commands = - -coverage combine --append - coverage html -d {envtmpdir} - coverage xml -o {envtmpdir}/coverage.xml - - -[testenv:lint] -basepython = python3.13 -deps = - {[dev]deps} - black - pylint - doc8 - Pygments - mypy - lxml - types-setuptools - types-PyYAML - -commands = - pylint --reports=y \ - --rcfile={toxinidir}/tox.ini \ - --output={envtmpdir}/pylint.txt \ - --output-format=json2 \ - --clear-cache-post-run=y \ - --confidence=HIGH \ - {toxinidir}/src/nunavut - black --check --line-length 120 --force-exclude '(/jinja2/|/markupsafe\/)' {toxinidir}/src - doc8 --ignore-path {toxinidir}/docs/cmake/build \ - --ignore-path {toxinidir}/docs/cmake/external \ - {toxinidir}/docs - mypy -p nunavut \ - --cache-dir {envtmpdir} \ - --txt-report {envtmpdir}/mypy-report-lib \ - --config-file {toxinidir}/tox.ini - - -[testenv:format] -basepython = python3.13 -deps = - {[dev]deps} - black - isort -commands = - isort --skip-glob '*/jinja2/*' --skip-glob '*/markupsafe/*' {toxinidir}/src/nunavut - black --line-length 120 --force-exclude '(/jinja2/|/markupsafe\/)' {toxinidir}/src - - -[testenv:package] -deps = - build - twine - setuptools - -commands = - python version_check_pydsdl.py -vv - python -m build \ - -o {toxworkdir}/package/dist \ - --sdist \ - --wheel \ - --config-setting=--build-number={env:GITHUB_RUN_ID:0} - twine check {toxworkdir}/package/dist/* - -[testenv:local] -usedevelop = true -deps = - {[base]deps} - {[dev]deps} - {[testenv:docs]deps} - {[testenv:lint]deps} -commands = - python --version diff --git a/verification/python/noxfile.py b/verification/python/noxfile.py index dd5db7c0..814371ce 100644 --- a/verification/python/noxfile.py +++ b/verification/python/noxfile.py @@ -108,7 +108,7 @@ def test(session): session.run( "mypy", "--strict", - f"--config-file={NUNAVUT_DIR / 'tox.ini'}", # Inherit the settings from the outer project. Not sure about it. + f"--config-file={NUNAVUT_DIR / 'pyproject.toml'}", # Inherit the settings from the outer project. str(SUITE_SRC_DIR), *[str(x) for x in generated_dir.iterdir() if x.is_dir() and x.name[0] not in "._"], )