From e284d5cf01750b861eb837993e3d6aca5c2c0c67 Mon Sep 17 00:00:00 2001 From: Joshua Oreman Date: Mon, 5 Jun 2023 11:00:57 -0600 Subject: [PATCH] Modernize CI --- .github/workflows/ci.yml | 54 +++++++++--- .travis.yml | 27 ------ README.rst | 2 +- check.sh | 6 +- ci.sh | 75 ++--------------- docs-requirements.txt | 144 ++++++++++++++++++++++---------- pyproject.toml | 22 +++++ setup.cfg | 2 - setup.py | 2 +- test-requirements.txt | 36 +++++--- tricycle/_meta.py | 2 +- tricycle/_rwlock.py | 2 +- tricycle/_service_nursery.py | 2 +- tricycle/_tests/test_meta.py | 2 +- tricycle/_tests/test_streams.py | 4 +- 15 files changed, 206 insertions(+), 176 deletions(-) delete mode 100644 .travis.yml delete mode 100644 setup.cfg diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f7bc08..739931a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,9 @@ name: CI on: + push: + branches: + - master pull_request: jobs: @@ -17,10 +20,20 @@ jobs: - name: Checkout uses: actions/checkout@v2 - name: Setup python - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: - python-version: '${{ matrix.python }}' + # This allows the matrix to specify just the major.minor version while still + # expanding it to get the latest patch version including alpha releases. + # This avoids the need to update for each new alpha, beta, release candidate, + # and then finally an actual release version. actions/setup-python doesn't + # support this for PyPy presently so we get no help there. + # + # CPython -> 3.9.0-alpha - 3.9.X + # PyPy -> pypy-3.7 + python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python), matrix.python))[startsWith(matrix.python, 'pypy')] }} architecture: '${{ matrix.arch }}' + cache: pip + cache-dependency-path: test-requirements.txt - name: Run tests run: ./ci.sh shell: bash @@ -35,28 +48,40 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.7', '3.8', '3.9', '3.10', '3.11'] - check_docs: ['0'] + python: ['pypy-3.8', 'pypy-3.9', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12-dev'] check_lint: ['0'] extra_name: [''] include: - - python: '3.8' - check_docs: '1' - extra_name: ', check docs' - python: '3.8' check_lint: '1' extra_name: ', formatting and linting' + continue-on-error: >- + ${{ + ( + matrix.check_formatting == '1' + || endsWith(matrix.python, '-dev') + ) + && true + || false + }} steps: - name: Checkout uses: actions/checkout@v2 - name: Setup python - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 + if: "!endsWith(matrix.python, '-dev')" + with: + python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python), matrix.python))[startsWith(matrix.python, 'pypy')] }} + cache: pip + cache-dependency-path: test-requirements.txt + - name: Setup python (dev) + uses: deadsnakes/action@v2.0.2 + if: endsWith(matrix.python, '-dev') with: python-version: '${{ matrix.python }}' - name: Run tests run: ./ci.sh env: - CHECK_DOCS: '${{ matrix.check_docs }}' CHECK_LINT: '${{ matrix.check_lint }}' # Should match 'name:' up above JOB_NAME: 'Ubuntu (${{ matrix.python }}${{ matrix.extra_name }})' @@ -69,13 +94,20 @@ jobs: fail-fast: false matrix: python: ['3.7', '3.8', '3.9', '3.10', '3.11'] + include: + - python: '3.8' # <- not actually used + arch: 'x64' + pypy_nightly_branch: 'py3.8' + extra_name: ', pypy 3.8 nightly' steps: - name: Checkout uses: actions/checkout@v2 - name: Setup python - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: - python-version: '${{ matrix.python }}' + python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python), matrix.python))[startsWith(matrix.python, 'pypy')] }} + cache: pip + cache-dependency-path: test-requirements.txt - name: Run tests run: ./ci.sh env: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 639ac4b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: python -dist: xenial - -matrix: - include: - # The pypy tests are slow, so we list them first - - python: pypy3.6-7.2.0 - dist: bionic - - language: generic - env: PYPY_NIGHTLY_BRANCH=py3.6 - - python: 3.6-dev - - python: 3.7-dev - - python: 3.8-dev - - # Disabled because we can't build typed-ast - #- python: 3.9-dev - - # Temporarily disabled during the high-churn period of 3.10 - # E.g.: https://github.com/MagicStack/immutables/issues/46 - #- python: nightly - -script: - - ./ci.sh - -branches: - except: - - /^dependabot/.*/ diff --git a/README.rst b/README.rst index ce9061e..039c7c4 100644 --- a/README.rst +++ b/README.rst @@ -36,7 +36,7 @@ cleanliness and good test coverage, please be advised that good idea at the time, and should be treated with according skepticism if you're contemplating using it in production. It hasn't necessarily been reviewed or tested to Trio's standards, it supports at minimum -Python 3.6, and some features might not be available on PyPy or on +Python 3.7, and some features might not be available on PyPy or on Windows. * If you find that it meets your needs, you're welcome to use it. We'll diff --git a/check.sh b/check.sh index 39f10e0..ae74bf3 100755 --- a/check.sh +++ b/check.sh @@ -5,8 +5,10 @@ set -ex EXIT_STATUS=0 # Autoformatter *first*, to avoid double-reporting errors -black --check setup.py tricycle \ - || EXIT_STATUS=$? +if ! black --check setup.py tricycle; then + EXIT_STATUS=1 + black --diff setup.py tricycle +fi # Run flake8 without pycodestyle and import-related errors flake8 tricycle/ \ diff --git a/ci.sh b/ci.sh index 4b2f828..08974a1 100755 --- a/ci.sh +++ b/ci.sh @@ -3,62 +3,14 @@ set -ex -o pipefail # Log some general info about the environment +uname -a env | sort -if [ "$SYSTEM_JOBIDENTIFIER" != "" ]; then - # azure pipelines - CODECOV_NAME="$SYSTEM_JOBIDENTIFIER" -else - CODECOV_NAME="${TRAVIS_OS_NAME}-${TRAVIS_PYTHON_VERSION:-unknown}" -fi - ################################################################ # Bootstrap python environment, if necessary ################################################################ -### Azure pipelines + Windows ### - -# On azure pipeline's windows VMs, to get reasonable performance, we need to -# jump through hoops to avoid touching the C:\ drive as much as possible. -if [ "$AGENT_OS" = "Windows_NT" ]; then - # By default temp and cache directories are on C:\. Fix that. - export TEMP="${AGENT_TEMPDIRECTORY}" - export TMP="${AGENT_TEMPDIRECTORY}" - export TMPDIR="${AGENT_TEMPDIRECTORY}" - export PIP_CACHE_DIR="${AGENT_TEMPDIRECTORY}\\pip-cache" - - # Download and install Python from scratch onto D:\, instead of using the - # pre-installed versions that azure pipelines provides on C:\. - # Also use -DirectDownload to stop nuget from caching things on C:\. - nuget install "${PYTHON_PKG}" -Version "${PYTHON_VERSION}" \ - -OutputDirectory "$PWD/pyinstall" -ExcludeVersion \ - -Source "https://api.nuget.org/v3/index.json" \ - -Verbosity detailed -DirectDownload -NonInteractive - - pydir="$PWD/pyinstall/${PYTHON_PKG}" - export PATH="${pydir}/tools:${pydir}/tools/scripts:$PATH" - - # Fix an issue with the nuget python 3.5 packages - # https://github.com/python-trio/trio/pull/827#issuecomment-457433940 - rm -f "${pydir}/tools/pyvenv.cfg" || true -fi - -### Travis + macOS ### - -if [ "$TRAVIS_OS_NAME" = "osx" ]; then - CODECOV_NAME="osx_${MACPYTHON}" - curl -Lo macpython.pkg https://www.python.org/ftp/python/${MACPYTHON}/python-${MACPYTHON}-macosx10.6.pkg - sudo installer -pkg macpython.pkg -target / - ls /Library/Frameworks/Python.framework/Versions/*/bin/ - PYTHON_EXE=/Library/Frameworks/Python.framework/Versions/*/bin/python3 - # The pip in older MacPython releases doesn't support a new enough TLS - curl https://bootstrap.pypa.io/get-pip.py | sudo $PYTHON_EXE - sudo $PYTHON_EXE -m pip install virtualenv - $PYTHON_EXE -m virtualenv testenv - source testenv/bin/activate -fi - -### PyPy nightly (currently on Travis) ### +### PyPy nightly ### if [ "$PYPY_NIGHTLY_BRANCH" != "" ]; then CODECOV_NAME="pypy_nightly_${PYPY_NIGHTLY_BRANCH}" @@ -101,14 +53,7 @@ python -m pip --version python setup.py sdist --formats=zip python -m pip install dist/*.zip -if [ "$CHECK_DOCS" = "1" ]; then - python -m pip install -r docs-requirements.txt - towncrier --yes # catch errors in newsfragments - cd docs - # -n (nit-picky): warn on missing references - # -W: turn warnings into errors - sphinx-build -nW -b html source build -elif [ "$CHECK_LINT" = "1" ]; then +if [ "$CHECK_LINT" = "1" ]; then python -m pip install -r test-requirements.txt source check.sh else @@ -119,16 +64,6 @@ else cd empty INSTALLDIR=$(python -c "import os, tricycle; print(os.path.dirname(tricycle.__file__))") - cp ../setup.cfg $INSTALLDIR - pytest -W error -ra --junitxml=../test-results.xml -o faulthandler_timeout=60 ${INSTALLDIR} --cov="$INSTALLDIR" --cov-config=../.coveragerc --verbose - - # Disable coverage on 3.8 until we run 3.8 on Windows CI too - # https://github.com/python-trio/trio/pull/784#issuecomment-446438407 - if [[ "$(python -V)" != Python\ 3.8* ]]; then - # Disable coverage on pypy py3.6 nightly for now: - # https://bitbucket.org/pypy/pypy/issues/2943/ - if [ "$PYPY_NIGHTLY_BRANCH" != "py3.6" ]; then - bash <(curl -s https://codecov.io/bash) -n "${CODECOV_NAME}" - fi - fi + cp ../pyproject.toml $INSTALLDIR + pytest -ra --junitxml=../test-results.xml ${INSTALLDIR} --cov="$INSTALLDIR" --cov-report=xml --cov-config=../.coveragerc --verbose fi diff --git a/docs-requirements.txt b/docs-requirements.txt index cac2c32..75694de 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -1,50 +1,108 @@ # -# This file is autogenerated by pip-compile -# To update, run: +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: # # pip-compile docs-requirements.in # -alabaster==0.7.12 # via sphinx -async-generator==1.10 # via trio -attrs==19.3.0 # via outcome, trio -babel==2.7.0 # via sphinx -certifi==2019.11.28 # via requests -chardet==3.0.4 # via requests -click==7.0 # via towncrier -docutils==0.15.2 # via sphinx -idna==2.8 # via requests, trio -imagesize==1.1.0 # via sphinx -incremental==17.5.0 # via towncrier -jinja2==2.10.3 # via sphinx, towncrier -markupsafe==1.1.1 # via jinja2 -mypy-extensions==0.4.3 # via mypy, trio-typing -mypy==0.782 # via trio-typing -outcome==1.0.1 # via trio -packaging==19.2 # via sphinx -pygments==2.5.2 # via sphinx -pyparsing==2.4.5 # via packaging -pytz==2019.3 # via babel -requests==2.22.0 # via sphinx -six==1.13.0 # via packaging -sniffio==1.1.0 # via trio -snowballstemmer==2.0.0 # via sphinx -sortedcontainers==2.1.0 # via trio -sphinx-rtd-theme==0.4.3 # via -r docs-requirements.in -sphinx==2.2.2 # via -r docs-requirements.in, sphinx-rtd-theme, sphinxcontrib-trio -sphinxcontrib-applehelp==1.0.1 # via sphinx -sphinxcontrib-devhelp==1.0.1 # via sphinx -sphinxcontrib-htmlhelp==1.0.2 # via sphinx -sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.2 # via sphinx -sphinxcontrib-serializinghtml==1.1.3 # via sphinx -sphinxcontrib-trio==1.1.0 # via -r docs-requirements.in -toml==0.10.0 # via towncrier -towncrier==19.2.0 # via -r docs-requirements.in -trio-typing==0.5.0 # via -r docs-requirements.in -trio==0.17.0 # via -r docs-requirements.in, trio-typing -typed-ast==1.4.0 # via mypy -typing-extensions==3.7.4.1 # via mypy, trio-typing -urllib3==1.25.7 # via requests + +alabaster==0.7.13 + # via sphinx +async-generator==1.10 + # via trio +attrs==23.1.0 + # via + # outcome + # trio +babel==2.12.1 + # via sphinx +certifi==2023.5.7 + # via requests +charset-normalizer==3.1.0 + # via requests +click==8.1.3 + # via + # click-default-group + # towncrier +click-default-group==1.2.2 + # via towncrier +docutils==0.18.1 + # via + # sphinx + # sphinx-rtd-theme +exceptiongroup==1.1.1 + # via trio +idna==3.4 + # via + # requests + # trio +imagesize==1.4.1 + # via sphinx +importlib-metadata==6.6.0 + # via sphinx +incremental==22.10.0 + # via towncrier +jinja2==3.1.2 + # via + # sphinx + # towncrier +markupsafe==2.1.3 + # via jinja2 +mypy-extensions==1.0.0 + # via trio-typing +outcome==1.2.0 + # via trio +packaging==23.1 + # via sphinx +pygments==2.15.1 + # via sphinx +requests==2.31.0 + # via sphinx +sniffio==1.3.0 + # via trio +snowballstemmer==2.2.0 + # via sphinx +sortedcontainers==2.4.0 + # via trio +sphinx==6.2.1 + # via + # -r docs-requirements.in + # sphinx-rtd-theme + # sphinxcontrib-jquery + # sphinxcontrib-trio +sphinx-rtd-theme==1.2.1 + # via -r docs-requirements.in +sphinxcontrib-applehelp==1.0.4 + # via sphinx +sphinxcontrib-devhelp==1.0.2 + # via sphinx +sphinxcontrib-htmlhelp==2.0.1 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.3 + # via sphinx +sphinxcontrib-serializinghtml==1.1.5 + # via sphinx +sphinxcontrib-trio==1.1.2 + # via -r docs-requirements.in +tomli==2.0.1 + # via towncrier +towncrier==22.12.0 + # via -r docs-requirements.in +trio==0.22.0 + # via + # -r docs-requirements.in + # trio-typing +trio-typing==0.8.0 + # via -r docs-requirements.in +typing-extensions==4.6.3 + # via trio-typing +urllib3==2.0.2 + # via requests +zipp==3.15.0 + # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/pyproject.toml b/pyproject.toml index d2690da..6a71f3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,28 @@ +[tool.black] +target-version = ['py37'] + [tool.towncrier] package = "tricycle" filename = "docs/source/history.rst" directory = "newsfragments" underlines = ["-", "~", "^"] issue_format = "`#{issue} `__" + +[tool.pytest.ini_options] +addopts = ["--strict-markers", "--strict-config"] +xfail_strict = true +faulthandler_timeout = 60 +junit_family = "xunit2" +filterwarnings = [ + "error", + # https://gitter.im/python-trio/general?at=63bb8d0740557a3d5c688d67 + 'ignore:You are using cryptography on a 32-bit Python on a 64-bit Windows Operating System. Cryptography will be significantly faster if you switch to using a 64-bit Python.:UserWarning', + # this should remain until https://github.com/pytest-dev/pytest/pull/10894 is merged + 'ignore:ast.Str is deprecated:DeprecationWarning', + 'ignore:Attribute s is deprecated and will be removed:DeprecationWarning', + 'ignore:ast.NameConstant is deprecated:DeprecationWarning', + 'ignore:ast.Num is deprecated:DeprecationWarning', + # https://github.com/python/mypy/issues/15330 + 'ignore:ast.Ellipsis is deprecated:DeprecationWarning', + 'ignore:ast.Bytes is deprecated:DeprecationWarning', +] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 2dd7538..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[tool:pytest] -xfail_strict = true diff --git a/setup.py b/setup.py index ee9ed25..da6590d 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ include_package_data=True, install_requires=["trio >= 0.15.0", "trio-typing >= 0.5.0"], keywords=["async", "trio"], - python_requires=">=3.6", + python_requires=">=3.7", classifiers=[ "License :: OSI Approved :: MIT License", "License :: OSI Approved :: Apache Software License", diff --git a/test-requirements.txt b/test-requirements.txt index c68d975..8b4b424 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,24 +1,28 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.9 # by the following command: # # pip-compile test-requirements.in # + async-generator==1.10 # via # -r test-requirements.in # trio -attrs==22.2.0 +attrs==23.1.0 # via # -r test-requirements.in - # pytest # trio -black==23.1.0 ; implementation_name == "cpython" +black==23.3.0 ; implementation_name == "cpython" # via -r test-requirements.in click==8.1.3 # via black -coverage[toml]==7.2.1 +coverage[toml]==7.2.7 # via pytest-cov +exceptiongroup==1.1.1 + # via + # pytest + # trio flake8==5.0.4 # via -r test-requirements.in idna==3.4 @@ -27,7 +31,7 @@ iniconfig==2.0.0 # via pytest mccabe==0.7.0 # via flake8 -mypy==1.0.1 ; implementation_name == "cpython" +mypy==1.3.0 ; implementation_name == "cpython" # via -r test-requirements.in mypy-extensions==1.0.0 # via @@ -38,13 +42,13 @@ outcome==1.2.0 # via # pytest-trio # trio -packaging==23.0 +packaging==23.1 # via # black # pytest -pathspec==0.11.0 +pathspec==0.11.1 # via black -platformdirs==3.0.0 +platformdirs==3.5.1 # via black pluggy==1.0.0 # via pytest @@ -52,12 +56,12 @@ pycodestyle==2.9.1 # via flake8 pyflakes==2.5.0 # via flake8 -pytest==7.2.1 +pytest==7.3.1 # via # -r test-requirements.in # pytest-cov # pytest-trio -pytest-cov==4.0.0 +pytest-cov==4.1.0 # via -r test-requirements.in pytest-trio==0.8.0 # via -r test-requirements.in @@ -65,14 +69,20 @@ sniffio==1.3.0 # via trio sortedcontainers==2.4.0 # via trio +tomli==2.0.1 + # via + # black + # mypy + # pytest trio==0.22.0 # via # -r test-requirements.in # pytest-trio # trio-typing -trio-typing==0.7.0 +trio-typing==0.8.0 # via -r test-requirements.in -typing-extensions==4.5.0 +typing-extensions==4.6.3 # via + # black # mypy # trio-typing diff --git a/tricycle/_meta.py b/tricycle/_meta.py index d5911e9..61ddf68 100644 --- a/tricycle/_meta.py +++ b/tricycle/_meta.py @@ -1,6 +1,6 @@ import abc import functools -from async_generator import asynccontextmanager +from contextlib import asynccontextmanager from trio import Nursery from typing import ( Any, diff --git a/tricycle/_rwlock.py b/tricycle/_rwlock.py index c78d013..c2a2e01 100644 --- a/tricycle/_rwlock.py +++ b/tricycle/_rwlock.py @@ -1,6 +1,6 @@ import attr import trio -from async_generator import asynccontextmanager +from contextlib import asynccontextmanager from collections import OrderedDict from typing import ( AsyncIterator, diff --git a/tricycle/_service_nursery.py b/tricycle/_service_nursery.py index 08e930e..1303df3 100644 --- a/tricycle/_service_nursery.py +++ b/tricycle/_service_nursery.py @@ -3,7 +3,7 @@ import trio from trio_typing import TaskStatus from functools import partial -from async_generator import asynccontextmanager +from contextlib import asynccontextmanager from typing import Any, AsyncIterator, Awaitable, Callable, Optional, overload from ._multi_cancel import MultiCancelScope diff --git a/tricycle/_tests/test_meta.py b/tricycle/_tests/test_meta.py index 993c47a..2ffa68f 100644 --- a/tricycle/_tests/test_meta.py +++ b/tricycle/_tests/test_meta.py @@ -3,7 +3,7 @@ import types import trio import trio.testing -from async_generator import asynccontextmanager +from contextlib import asynccontextmanager from typing import Any, AsyncIterator, Coroutine, Iterator, List from trio_typing import TaskStatus diff --git a/tricycle/_tests/test_streams.py b/tricycle/_tests/test_streams.py index 9d5a49e..35ad605 100644 --- a/tricycle/_tests/test_streams.py +++ b/tricycle/_tests/test_streams.py @@ -5,9 +5,10 @@ import trio import trio.testing -from async_generator import asynccontextmanager +from contextlib import asynccontextmanager from functools import partial from typing import ( + AsyncContextManager, AsyncIterator, Awaitable, Callable, @@ -17,7 +18,6 @@ Tuple, cast, ) -from typing_extensions import AsyncContextManager from .. import BufferedReceiveStream, TextReceiveStream