diff --git a/.github/workflows/test-other.yaml b/.github/workflows/test-other.yaml new file mode 100644 index 000000000..4e8289263 --- /dev/null +++ b/.github/workflows/test-other.yaml @@ -0,0 +1,48 @@ +# Other tests, primarily those requiring obsolete dependencies. +name: test-other + +on: + push: + branches: + - "*" + +jobs: + run-tox: + name: tox -e ${{ matrix.toxenv }} + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + python-version: + - "3.8" + toxenv: + - "py38_smoke" + - "py38_smoke_cython" + - "wsgi_meinheld" + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install smoke test dependencies + run: | + sudo apt-get update + sudo apt-get install -y libunwind-dev + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade setuptools tox wheel + python --version + pip --version + tox --version + + - name: Run tox + run: tox -e ${{ matrix.toxenv }} diff --git a/.github/workflows/test-wheels.yaml b/.github/workflows/test-wheels.yaml index 3ccf2e360..43c7644a7 100644 --- a/.github/workflows/test-wheels.yaml +++ b/.github/workflows/test-wheels.yaml @@ -22,6 +22,8 @@ jobs: - build: "cp313-manylinux_s390x" os: ubuntu-latest emulation: true + - build: "cp38-manylinux_x86_64" + os: ubuntu-latest - build: "cp313-musllinux_x86_64" os: ubuntu-latest - build: "cp313-macosx_arm64" diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 078e5f59a..47ece6bef 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,4 +1,5 @@ -name: Run tests +# Run tests in various tox environments. +name: tests on: # NOTE(vytas): Trigger the tests workflow on push or pull request @@ -11,104 +12,73 @@ on: - master jobs: - run_tox: - name: tox -e ${{ matrix.toxenv }} (${{matrix.python-version}} on ${{ matrix.os }}) - runs-on: ${{ matrix.os }} + run-tox: + name: tox -e ${{ matrix.tox.env }}${{ matrix.tox.platform-label || '' }} + runs-on: ${{ matrix.tox.os || matrix.default-os }} strategy: fail-fast: false matrix: + default-os: + - "ubuntu-latest" python-version: - "3.12" - python-dev-version: - - "" - os: - - "ubuntu-latest" - toxenv: - - "pep8" - - "pep8-docstrings" - - "pep8-examples" - - "ruff" - - "mypy" - - "mypy_tests" - - "py312" - - "py312_sans_msgpack" - - "py312_cython" - - "docs" - - "towncrier" - - "look" - - "asgilook" - - "ws_tutorial" - # NOTE(vytas): Temporarily disabled while we are releasing a - # new version of python-mimeparse, and haven't decided yet whether - # to keep vendoring or reimplement. - # - "check_vendored" - - "twine_check" - - "daphne" - - "hypercorn" - - "e2e_chrome" - - "e2e_firefox" - - "no_optional_packages" - # TODO(kgriffs): Re-enable once hug has a chance to address - # breaking changes in Falcon 3.0 - # - "hug" - include: - - python-version: pypy3.9 - os: ubuntu-latest - toxenv: pypy3 - - python-version: "3.8" - os: ubuntu-latest - toxenv: py38 - - python-version: "3.9" - os: ubuntu-latest - toxenv: py39 - - python-version: "3.9" - os: ubuntu-latest - toxenv: py39_cython - - python-version: "3.10" - os: ubuntu-latest - toxenv: py310 - - python-version: "3.10" - os: ubuntu-latest - toxenv: py310_cython - - python-version: "3.11" - os: ubuntu-latest - toxenv: py311 - - python-version: "3.11" - os: ubuntu-latest - toxenv: py311_cython - - python-version: "3.12" - os: ubuntu-latest - toxenv: py312 - - python-version: "3.12" - os: ubuntu-latest - toxenv: py312_cython - - python-version: "3.12" + tox: + # Lint + - env: pep8 + - env: pep8-docstrings + - env: ruff + # Documentation + - env: docs + - env: towncrier + # Typing + - env: mypy + - env: mypy_tests + # Python tests + - env: mintest + coverage: true + - env: pypy3 + python-version: "pypy3.10" + - env: py38 + python-version: "3.8" + - env: py39 + python-version: "3.9" + - env: py310 + python-version: "3.10" + - env: py310_cython + python-version: "3.10" + - env: py311 + python-version: "3.11" + - env: py311_cython + python-version: "3.11" + - env: py312 + coverage: true + python-version: "3.12" + - env: py312_cython + python-version: "3.12" + - env: py313 + python-version: "3.13.0-rc.3 - 3.13" + - env: py313_cython + python-version: "3.13.0-rc.3 - 3.13" + - env: py312_nocover os: macos-latest - toxenv: py312_nocover - - python-version: "3.12" + platform-label: ' (macos)' + - env: py312_nocover os: windows-latest - toxenv: py312_nocover - - python-version: "3.13" - python-dev-version: "3.13.0-rc.1 - 3.13" - os: ubuntu-latest - toxenv: py313 - - python-version: "3.13" - python-dev-version: "3.13.0-rc.1 - 3.13" - os: ubuntu-latest - toxenv: py313_cython - # These env require 3.8 and 20.04, see tox.ini - - python-version: "3.8" - os: ubuntu-20.04 - toxenv: py38_smoke - - python-version: "3.8" - os: ubuntu-20.04 - toxenv: py38_smoke_cython - - python-version: "3.8" - os: ubuntu-latest - toxenv: "wsgi_servers" + platform-label: ' (windows)' + # Tutorials + - env: "look" + - env: "asgilook" + - env: "ws_tutorial" + # Tooling + - env: "twine_check" + # ASGI & WSGI servers + - env: "daphne" + - env: "hypercorn" + - env: "wsgi_servers" + # E2E tests + - env: "e2e_chrome" + - env: "e2e_firefox" - # Steps to run in each job. - # Some are GitHub actions, others run shell commands. steps: - name: Checkout repo uses: actions/checkout@v4 @@ -119,43 +89,30 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 - if: ${{ !matrix.python-dev-version }} with: - python-version: ${{ matrix.python-version }} - - - name: Set up Python (pre-release) - uses: actions/setup-python@v5 - if: ${{ matrix.python-dev-version }} - with: - python-version: ${{ matrix.python-dev-version }} - - - name: Install smoke test dependencies - if: ${{ matrix.toxenv == 'py38_smoke' || matrix.toxenv == 'py38_smoke_cython' }} - run: | - sudo apt-get update - sudo apt-get install -y libunwind-dev + python-version: ${{ matrix.tox.python-version || matrix.python-version }} - - name: Install dependencies + - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install -U coverage fixtures setuptools tox wheel + pip install --upgrade coverage setuptools tox wheel python --version pip --version tox --version coverage --version - - name: Run tests - run: tox -e ${{ matrix.toxenv }} + - name: Run tox + run: tox -e ${{ matrix.tox.env }} - name: Combine coverage - if: ${{ matrix.toxenv == 'py312' || matrix.toxenv == 'py312_sans_msgpack' }} + if: ${{ matrix.tox.coverage }} run: | coverage --version coverage combine - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 - if: ${{ matrix.toxenv == 'py312' || matrix.toxenv == 'py312_sans_msgpack' }} + if: ${{ matrix.tox.coverage }} with: env_vars: PYTHON fail_ci_if_error: true diff --git a/.github/workflows/mintest.yaml b/.github/workflows/tox-sdist.yaml similarity index 96% rename from .github/workflows/mintest.yaml rename to .github/workflows/tox-sdist.yaml index c3a6b5f78..0986fc841 100644 --- a/.github/workflows/mintest.yaml +++ b/.github/workflows/tox-sdist.yaml @@ -1,4 +1,4 @@ -name: Run tests (contributor's checklist) +name: test-tox-sdist on: # Trigger the workflow on master but also allow it to run manually. diff --git a/README.rst b/README.rst index 996555128..dfa18e0c6 100644 --- a/README.rst +++ b/README.rst @@ -4,7 +4,7 @@ :target: https://falconframework.org/ :width: 100 % -|Build Status| |Docs| |codecov.io| +|Build status| |Docs| |codecov.io| |PyPI package| |Python versions| The Falcon Web Framework ======================== @@ -978,13 +978,17 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +.. |Build status| image:: https://github.com/falconry/falcon/actions/workflows/tests.yaml/badge.svg + :target: https://github.com/falconry/falcon/actions/workflows/tests.yaml .. |Docs| image:: https://readthedocs.org/projects/falcon/badge/?version=stable :alt: Falcon web framework docs :target: https://falcon.readthedocs.io/en/stable/?badge=stable -.. |Build Status| image:: https://github.com/falconry/falcon/workflows/Run%20tests/badge.svg - :target: https://github.com/falconry/falcon/actions?query=workflow%3A%22Run+tests%22 .. |codecov.io| image:: https://codecov.io/gh/falconry/falcon/branch/master/graphs/badge.svg - :target: http://codecov.io/gh/falconry/falcon + :target: https://codecov.io/gh/falconry/falcon +.. |PyPI package| image:: https://badge.fury.io/py/falcon.svg + :target: https://pypi.org/project/falcon/ +.. |Python versions| image:: https://img.shields.io/pypi/pyversions/falcon.svg + :target: https://pypi.org/project/falcon/ .. |Backer:GovCert| image:: https://falconframework.org/assets/govcert.png :alt: CERT Gouvernemental Luxembourg :height: 60px diff --git a/tools/testing/install_hug.sh b/tools/testing/install_hug.sh deleted file mode 100755 index 67e1ab8eb..000000000 --- a/tools/testing/install_hug.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -HUG_PATH=.ecosystem/hug - -# Clean up in case we are running locally and not in CI -rm -rf $HUG_PATH - -mkdir -p .ecosystem -git clone https://github.com/timothycrosley/hug.git $HUG_PATH -virtualenv $HUG_PATH/.venv -source $HUG_PATH/.venv/bin/activate - -pip install hug - -pushd $HUG_PATH -git checkout master -git pull -HUG_VERSION=$(pip freeze | grep hug | cut -c 6-) -git checkout tags/$HUG_VERSION -pip install -rrequirements/build.txt -popd - -pip install . # Override Hug's Falcon version with the one under test diff --git a/tools/testing/test_hug.sh b/tools/testing/test_hug.sh deleted file mode 100755 index 85d656e5a..000000000 --- a/tools/testing/test_hug.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -set -e - -pushd .ecosystem/hug -source .venv/bin/activate -python -m pytest tests -popd diff --git a/tox.ini b/tox.ini index 0b96f9d77..560f78f30 100644 --- a/tox.ini +++ b/tox.ini @@ -15,6 +15,7 @@ envlist = cleanup, ruff, pep8, + pep8-docstrings, mypy, mypy_tests, mintest, @@ -48,29 +49,6 @@ commands = coverage combine coverage html -d {toxinidir}/.coverage_html coverage report --fail-under 100 -# -------------------------------------------------------------------- -# ASGI servers -# -------------------------------------------------------------------- - -[testenv:daphne] -deps = {[testenv]deps} - daphne - -[testenv:hypercorn] -# TODO(vytas): Unpin Hypercorn once the buggy versions are yanked upstream. -deps = {[testenv]deps} - hypercorn != 0.14.0, != 0.14.1 - -# -------------------------------------------------------------------- -# Test without optional packages -# -------------------------------------------------------------------- - -[testenv:no_optional_packages] -deps = {[testenv]deps} -commands = python "{toxinidir}/tools/clean.py" "{toxinidir}/falcon" - pip uninstall --yes python-rapidjson daphne orjson - pytest tests [] - # -------------------------------------------------------------------- # Coverage # -------------------------------------------------------------------- @@ -93,11 +71,6 @@ deps = {[testenv]deps} jsonschema commands = coverage run -m pytest tests [] -[testenv:pytest_sans_msgpack] -deps = {[testenv]deps} -commands = pip uninstall --yes msgpack - coverage run -m pytest tests -k "test_ws and test_msgpack_missing" - [testenv:py312] basepython = python3.12 deps = {[testenv]deps} @@ -105,12 +78,6 @@ deps = {[testenv]deps} jsonschema commands = {[with-coverage]commands} -[testenv:py312_sans_msgpack] -basepython = python3.12 -deps = {[testenv]deps} -commands = pip uninstall --yes msgpack - coverage run -m pytest tests -k "test_ws and test_msgpack_missing" - [testenv:py312_nocover] basepython = python3.12 deps = {[testenv]deps} @@ -134,13 +101,13 @@ deps = -r{toxinidir}/requirements/tests pdbpp [testenv:py3_debug] -basepython = python3.10 +basepython = python3.12 deps = {[with-debug-tools]deps} uvicorn jsonschema # -------------------------------------------------------------------- -# mypy +# Mypy # -------------------------------------------------------------------- [testenv:mypy] @@ -229,12 +196,33 @@ commands = {[with-cython]commands} setenv = {[with-cython]setenv} deps = {[with-cython]deps} gunicorn - # NOTE(caselit): meinheld requires greenlet<0.5 that's not compatible with py3.10 - meinheld uwsgi waitress commands = pytest -v tests/test_wsgi_servers.py +[testenv:wsgi_meinheld] +# NOTE(caselit): meinheld requires greenlet<0.5 that's not compatible with py3.10 +basepython = python3.8 +setenv = {[with-cython]setenv} +deps = {[with-cython]deps} + gunicorn + meinheld +commands = pytest -v tests/test_wsgi_servers.py + +# -------------------------------------------------------------------- +# ASGI servers +# -------------------------------------------------------------------- + +[testenv:daphne] +deps = {[testenv]deps} + daphne +commands = pytest -v tests/asgi/test_asgi_servers.py + +[testenv:hypercorn] +deps = {[testenv]deps} + hypercorn +commands = pytest -v tests/asgi/test_asgi_servers.py + # -------------------------------------------------------------------- # Smoke testing with a sample app # -------------------------------------------------------------------- @@ -266,8 +254,17 @@ commands = {[smoke-test]commands} [testenv:pep8] deps = ruff +skip_install = True commands = ruff check [] +[testenv:pep8-docstrings] +deps = ruff +skip_install = True +commands = ruff check \ + --exclude=.ecosystem,.eggs,.git,.tox,.venv,build,dist,docs,examples,tests,falcon/vendor,falcon/bench/nuts \ + --select=D205,D212,D400,D401,D403,D404 \ + [] + [testenv:ruff] deps = ruff>=0.3.7 skip_install = True @@ -276,35 +273,23 @@ commands = ruff format --check . [] [testenv:reformat] deps = ruff>=0.3.7 skip_install = True -commands = ruff format . [] - -[testenv:pep8-docstrings] -deps = ruff -commands = ruff check \ - --exclude=.ecosystem,.eggs,.git,.tox,.venv,build,dist,docs,examples,tests,falcon/vendor,falcon/bench/nuts \ - --select=D205,D212,D400,D401,D403,D404 \ - [] - -[testenv:pep8-examples] -deps = ruff -commands = ruff check examples [] +commands = + ruff format . [] + ruff check --fix # -------------------------------------------------------------------- # For viewing environ dicts generated by various WSGI servers # -------------------------------------------------------------------- -[testenv:py310_dump_gunicorn] -basepython = python3.10 +[testenv:dump_gunicorn] deps = gunicorn commands = gunicorn -b localhost:8000 tests.dump_wsgi -[testenv:py310_dump_waitress] -basepython = python3.10 +[testenv:dump_waitress] deps = waitress commands = waitress-serve --listen=localhost:8000 tests.dump_wsgi:application -[testenv:py310_dump_wsgiref] -basepython = python3.10 +[testenv:dump_wsgiref] commands = python tests/dump_wsgi.py # -------------------------------------------------------------------- @@ -358,13 +343,11 @@ commands = {toxinidir}/tools/check-vendored.sh # -------------------------------------------------------------------- [testenv:twine_check] -basepython = python3.10 skipsdist = True -deps = setuptools +deps = build twine - wheel commands = - python {toxinidir}/setup.py bdist_wheel sdist + python -m build twine check {toxinidir}/dist/* # -------------------------------------------------------------------- @@ -414,7 +397,11 @@ commands = {toxinidir}/tools/generate_dash.sh # -------------------------------------------------------------------- -# Tutorial ("look") tests +# Tutorial tests +# +# - Tutorial ("look") tests +# - ASGI tutorial ("asgilook") tests +# - WebSockets tutorial ("ws_tutorial") tests # -------------------------------------------------------------------- [testenv:look] @@ -423,10 +410,6 @@ deps = commands = pytest {toxinidir}/examples/look/tests -# -------------------------------------------------------------------- -# ASGI tutorial ("asgilook") tests -# -------------------------------------------------------------------- - [testenv:asgilook] basepython = python3.12 deps = @@ -440,10 +423,6 @@ commands = --cov-report term-missing \ {toxinidir}/examples/asgilook/tests/ -# -------------------------------------------------------------------- -# WebSockets tutorial ("ws_tutorial") tests -# -------------------------------------------------------------------- - [testenv:ws_tutorial] basepython = python3.12 deps = @@ -457,17 +436,6 @@ commands = --cov-report term-missing \ {toxinidir}/examples/ws_tutorial/tests/ -# -------------------------------------------------------------------- -# Ecosystem -# -------------------------------------------------------------------- - -[testenv:hug] -basepython = python3.8 -deps = virtualenv -commands = - {toxinidir}/tools/testing/install_hug.sh - {toxinidir}/tools/testing/test_hug.sh - # -------------------------------------------------------------------- # E2E tests # -------------------------------------------------------------------- @@ -485,4 +453,3 @@ deps = -r{toxinidir}/requirements/e2e commands = pytest {toxinidir}/e2e-tests/ --browser=firefox -