diff --git a/.github/workflows/pull-request-ci.yml b/.github/workflows/pull-request-ci.yml index 5c781e4..61a4b3a 100644 --- a/.github/workflows/pull-request-ci.yml +++ b/.github/workflows/pull-request-ci.yml @@ -20,7 +20,7 @@ jobs: strategy: max-parallel: 3 matrix: - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.11", "3.12", "3.13"] uses: ./.github/workflows/reusable-ci-workflows.yml with: diff --git a/.github/workflows/reusable-ci-workflows.yml b/.github/workflows/reusable-ci-workflows.yml index 2a637ed..a29849a 100644 --- a/.github/workflows/reusable-ci-workflows.yml +++ b/.github/workflows/reusable-ci-workflows.yml @@ -41,8 +41,10 @@ jobs: - name: Run pylint run: | - pylint --score=yes --load-plugins=pylint.extensions.mccabe --max-complexity=$COMPLEXITY_MAX_SCORE $SOURCE_DIRS | tee pylint-${{ inputs.python-version }}.log - PYLINT_SCORE=$(tail -n 2 pylint-${{ inputs.python-version }}.log | grep -o '[0-9]\{1,2\}\.[0-9]\{2\}' | head -n 1) + pylint --score=yes --load-plugins=pylint.extensions.mccabe --max-complexity=$COMPLEXITY_MAX_SCORE \ + $SOURCE_DIRS | tee pylint-${{ inputs.python-version }}.log + PYLINT_SCORE=$(tail -n 2 pylint-${{ inputs.python-version }}.log \ + | grep -o '[0-9]\{1,2\}\.[0-9]\{2\}' | head -n 1) echo "Pylint score: $PYLINT_SCORE" exit $(echo "$PYLINT_SCORE < $PYLINT_MIN_SCORE" | bc) - name: Upload pylint results @@ -54,7 +56,8 @@ jobs: - name: Run mypy run: | mypy --namespace-packages $SOURCE_DIRS | tee mypy-${{ inputs.python-version }}.log - if [ -n "$(tail -n 1 mypy-${{ inputs.python-version }}.log | grep -e '^Succes')" ]; then RESULT="pass"; else RESULT="fail"; fi + if [ -n "$(tail -n 1 mypy-${{ inputs.python-version }}.log | grep -e '^Succes')" ]; \ + then RESULT="pass"; else RESULT="fail"; fi echo "Mypy result: $RESULT" exit $([[ "$RESULT" == "pass" ]] && echo 0 || echo 1) - name: Upload mypy results @@ -65,6 +68,8 @@ jobs: - name: Run coverage run: | + if [[ ${{ inputs.python-version }} == "3.13" ]]; \ + then pip install https://github.com/da4089/py-xdrlib/archive/refs/heads/main.zip; fi coverage run --branch --source=$SOURCE_DIRS -m unittest discover --start-directory=tests --pattern="test_*.py" coverage report --show-missing --fail-under=$COVERAGE_MIN_PERC | tee coverage-${{ inputs.python-version }}.log COVERAGE_PERC=$(grep "TOTAL" coverage-${{ inputs.python-version }}.log | grep -Eo '[0-9.]+%' | sed 's/%//') diff --git a/.github/workflows/scheduled-full-ci.yml b/.github/workflows/scheduled-full-ci.yml index e444742..781f417 100644 --- a/.github/workflows/scheduled-full-ci.yml +++ b/.github/workflows/scheduled-full-ci.yml @@ -10,7 +10,7 @@ jobs: strategy: max-parallel: 1 matrix: - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.11", "3.12", "3.13"] uses: ./.github/workflows/reusable-ci-workflows.yml with: @@ -29,6 +29,8 @@ jobs: - name: Run unit tests and generate report if: always() run: | + if [[ ${{ matrix.python-version }} == "3.13" ]]; \ + then pip install https://github.com/da4089/py-xdrlib/archive/refs/heads/main.zip; fi pip install . pip install unittest-xml-reporting python -m xmlrunner --output-file testresults.xml discover --start-directory=tests --pattern="test_*.py" diff --git a/.readthedocs.yml b/.readthedocs.yml index f3f8726..c467f40 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -7,7 +7,7 @@ sphinx: build: os: ubuntu-22.04 tools: - python: "3.10" + python: "3.11" python: install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 538a287..dbaca2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,14 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## \[x.y.z] - Unreleased ### Added -- Python 3.12 support +- Python 3.12, 3.13 support. +- installing of `py-xdrlib` from Github source for Python 3.13 unit-tests. ### Changed +- `qmi_tool` script entry point to be at `main` function. ### Fixed ### Removed -- Python 3.8 and 3.9 support, numpy and scipy version restrictions in dependencies. +- Python 3.8, 3.9 and 3.10 support, numpy and scipy version restrictions in dependencies. +- `qmi_run_contexts` script as unused. ## [0.46.0] - 2024-10-14 diff --git a/TESTING.md b/TESTING.md index 256ddee..9810594 100644 --- a/TESTING.md +++ b/TESTING.md @@ -26,7 +26,7 @@ In any case, both tools can be run from the command line: Unit tests ---------- -Unit tests are executed in the CI environment against different Python versions: 3.10, 3.11 and 3.12. Code coverage of +Unit tests are executed in the CI environment against different Python versions: 3.11, 3.12 and 3.13. Code coverage of the tests is computed using [Coverage.py](https://coverage.readthedocs.io/en/coverage-5.3.1/). To run the tests locally, use: ```zsh @@ -44,10 +44,10 @@ to the repository. The pipelines are configured in `.github\workflows` and consists of four files: - 1. push-ci.yml - 2. pull_request-ci.yml - 3. scheduled-full-ci.yml - 4. pypi_publish.yml + 1. `push-ci.yml` + 2. `pull_request-ci.yml` + 3. `scheduled-full-ci.yml` + 4. `pypi_publish.yml` with a support file `reusable-ci-workflows.yml`. @@ -55,7 +55,7 @@ In the first three workflows, the following tests are performed: - The code quality and maintainability analyses and unit-test coverage are performed, as these metrics are considered as quality indicators for the code base (which includes tests). - Unit-tests are performed and the coverage is calculated. -- On push to a branch, tests are executing only with Python 3.11. When changes are pushed to a pull request, the tests are rerun parallel also with Python 3.10, 3.11 and 3.12. With the 3.11 version, the quality badges are created. +- On push to a branch, tests are executing only with Python 3.11. When changes are pushed to a pull request, the tests are rerun parallel also with Python 3.12 and 3.13. With the 3.11 version, the quality badges are created. The fourth workflow packages the source code into an installable Python package. diff --git a/bin/qmi_run_contexts b/bin/qmi_run_contexts deleted file mode 100644 index 18ef2ed..0000000 --- a/bin/qmi_run_contexts +++ /dev/null @@ -1,43 +0,0 @@ -#! /usr/bin/env python3 - -import sys -import argparse -import time - -from qmi.core.context import QMI_Context - - -def main() -> int: - parser = argparse.ArgumentParser(description="Start some QMI_Contexts, waits, then stops the contexts.") - - parser.add_argument("--numcontexts", action='store', default=1, type=int, help="The number of contexts to make.") - parser.add_argument("--sleep", action='store', default=60.0, type=float, help="Time keep the context alive (seconds).") - - args = parser.parse_args() - - num_contexts = args.numcontexts - sleeptime = args.sleep - - contexts = [] - - print("Instantiating {} contexts ...".format(num_contexts)) - for i in range(num_contexts): - context_name = "context_{}".format(i + 1) - context = QMI_Context(context_name) - contexts.append(context) - - print("Starting contexts ...") - for (i, context) in enumerate(contexts): - context.start() - - try: - print("waiting for {:.3f} seconds ...".format(sleeptime)) - time.sleep(sleeptime) - finally: - print("Stopping contexts ...") - for context in contexts: - context.stop() - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/bin/qmi_tool b/bin/qmi_tool index c1caec8..0cf92b9 100644 --- a/bin/qmi_tool +++ b/bin/qmi_tool @@ -72,7 +72,7 @@ def hard_kill(): udp_socket.close() -if __name__ == "__main__": +def main(): for e, arg in enumerate(sys.argv[1:]): if arg == "ls": if len(sys.argv) == (e + 3): @@ -101,3 +101,7 @@ if __name__ == "__main__": if arg == "hard-kill-yes-really-i-am-sure": hard_kill() + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/documentation/sphinx/source/installation.rst b/documentation/sphinx/source/installation.rst index fb10e09..f83a3e4 100644 --- a/documentation/sphinx/source/installation.rst +++ b/documentation/sphinx/source/installation.rst @@ -15,7 +15,7 @@ Dependencies .. rubric:: Python version -QMI depends on Python 3.10 or newer. +QMI depends on Python 3.11 or newer. .. rubric:: Python packages diff --git a/setup.py b/setup.py index 18fa936..6d08691 100644 --- a/setup.py +++ b/setup.py @@ -35,9 +35,9 @@ def read(*names, **kwargs): "Operating System :: Microsoft :: Windows", "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 :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Scientific/Engineering :: Physics", @@ -49,7 +49,7 @@ def read(*names, **kwargs): keywords=[ # eg: 'keyword1', 'keyword2', 'keyword3', ], - python_requires=">=3.10, <4", + python_requires=">=3.11, <4", install_requires=[ # For generating an installable package and deploying "setuptools", @@ -98,7 +98,6 @@ def read(*names, **kwargs): }, scripts=[ "bin/qmi_tool", - "bin/qmi_run_contexts", "bin/qmi_hdf5_to_mat", "bin/instruments/qmi_anapico_apsin", "bin/instruments/qmi_mcc_usb1808x",