diff --git a/.appveyor.yml b/.appveyor.yml index 8af60b9b..7661aa63 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,14 +9,6 @@ environment: - TOXENV: py35-optional - TOXENV: py36-base - TOXENV: py36-optional - - TOXENV: py37-base - - TOXENV: py37-optional - - TOXENV: py38-base - - TOXENV: py38-optional - - TOXENV: py39-base - - TOXENV: py39-optional - - TOXENV: py310-base - - TOXENV: py310-optional install: - git submodule update --init --recursive diff --git a/.github/workflows/python-tox.yml b/.github/workflows/python-tox.yml index 0e3e46db..cfcc42e6 100644 --- a/.github/workflows/python-tox.yml +++ b/.github/workflows/python-tox.yml @@ -4,21 +4,62 @@ jobs: # Prevent duplicate builds for 'internal' pull requests on existing commits # Credit: https://github.community/t/duplicate-checks-on-push-and-pull-request-simultaneous-event/18012 if: github.event.push || github.event.pull_request.head.repo.full_name != github.repository - runs-on: ubuntu-latest strategy: fail-fast: false matrix: - python: ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy-2.7", "pypy-3.8"] + # 2.7, 3.5, and 3.6 run on Windows via AppVeyor + python: ["3.7", "3.8", "3.9", "3.10", "3.11"] + os: [ubuntu-latest, windows-latest] + deps: [base, optional] + include: + - python: "pypy-2.7" + os: ubuntu-latest + deps: base + - python: "pypy-3.8" + os: ubuntu-latest + deps: base + - python: "2.7" + os: ubuntu-latest + deps: oldest + - python: "3.7" + os: ubuntu-latest + deps: oldest + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 with: submodules: true - - uses: actions/setup-python@v4 + - if: ${{ matrix.deps == 'base' }} + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} cache: pip - cache-dependency-path: "requirements*.txt" + cache-dependency-path: | + requirements.txt + requirements-test.txt + - if: ${{ matrix.deps == 'optional' }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + cache: pip + cache-dependency-path: | + requirements.txt + requirements-optional.txt + requirements-test.txt + - if: ${{ matrix.deps == 'oldest' }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + cache: pip + cache-dependency-path: | + requirements-oldest.txt + - if: ${{ matrix.os == 'windows-latest' }} + name: Determine environment name for Tox (PowerShell) + run: python toxver.py ${{ matrix.python }} ${{ matrix.deps }} >> $env:GITHUB_ENV + - if: ${{ matrix.os == 'ubuntu-latest' }} + name: Determine environment name for Tox (Bash) + run: python toxver.py ${{ matrix.python }} ${{ matrix.deps }} >> $GITHUB_ENV - run: pip install tox - - run: tox -e py + - run: tox - if: ${{ always() }} run: python debug-info.py diff --git a/requirements-install.sh b/requirements-install.sh deleted file mode 100755 index b7a8d96d..00000000 --- a/requirements-install.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -ex - -if [[ $SIX_VERSION ]]; then - pip install six==$SIX_VERSION -fi - -pip install -r requirements-test.txt - -if [[ $USE_OPTIONAL == "true" ]]; then - pip install -r requirements-optional.txt -fi - -if [[ $CI == "true" ]]; then - pip install codecov -fi diff --git a/requirements-oldest.txt b/requirements-oldest.txt new file mode 100644 index 00000000..68d0f13d --- /dev/null +++ b/requirements-oldest.txt @@ -0,0 +1,29 @@ +# This allows us to install the actually oldest supported dependencies and test whether that works. + +# requirements.txt +six==1.9 +webencodings==0.5.1 + +# requirements-optional.txt +genshi==0.7.1 ; python_version < '3.8' +genshi==0.7.6 ; python_version >= '3.8' +chardet==2.2.1 +# this should be 3.4.0 but there are no Linux +# binary wheels for older releases +lxml==3.8.0 ; python_version < '3.7' +# minimums for 3.x are actually different: +# - 3.7 is actually 4.1.1 +# - 3.8 is actually 4.3.5 +# - 3.9-3.10 is actually 4.5.2 +# - 3.11 is actually 4.9.0 +lxml==4.9.0 ; python_version >= '3.7' + +# requirements-test.txt +flake8==3.9.2 ; python_version < '3.6' +flake8==5.0.4; python_version >= '3.6' +pytest==4.6.10 ; python_version < '3' +pytest==5.4.2 ; python_version >= '3' +coverage==5.1 +pytest-expect==1.1.0 +mock==3.0.5 ; python_version < '3.6' +mock==4.0.2 ; python_version >= '3.6' \ No newline at end of file diff --git a/requirements-optional.txt b/requirements-optional.txt index 2e78c952..2e112e95 100644 --- a/requirements-optional.txt +++ b/requirements-optional.txt @@ -2,12 +2,12 @@ # We support a Genshi treewalker that can be used to serialize Genshi # streams. -genshi +genshi>=0.7.1 # chardet can be used as a fallback in case we are unable to determine # the encoding of a document. -chardet>=2.2 +chardet>=2.2.1 # lxml is supported with its own treebuilder ("lxml") and otherwise # uses the standard ElementTree support -lxml ; platform_python_implementation == 'CPython' +lxml>=3.4.0 ; platform_python_implementation == 'CPython' diff --git a/requirements-test.txt b/requirements-test.txt index 8c0ca7c7..27866e59 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,7 +1,7 @@ -r requirements.txt -tox>=3.15.1,<4 -flake8>=3.8.1,<6 +flake8==3.9.2 ; python_version < '3.6' +flake8>=5.0.4; python_version >= '3.6' pytest>=4.6.10,<5 ; python_version < '3' pytest>=5.4.2,<7 ; python_version >= '3' coverage>=5.1,<6 diff --git a/setup.py b/setup.py index b4c11811..30ee0575 100644 --- a/setup.py +++ b/setup.py @@ -108,23 +108,23 @@ def default_environment(): packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]), install_requires=[ 'six>=1.9', - 'webencodings', + 'webencodings>=0.5.1', ], python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", extras_require={ # A conditional extra will only install these items when the extra is # requested and the condition matches. - "lxml:platform_python_implementation == 'CPython'": ["lxml"], + "lxml:platform_python_implementation == 'CPython'": ["lxml>=3.4.0"], # Standard extras, will be installed when the extra is requested. - "genshi": ["genshi"], - "chardet": ["chardet>=2.2"], + "genshi": ["genshi>=0.7.1"], + "chardet": ["chardet>=2.2.1"], # The all extra combines a standard extra which will be used anytime # the all extra is requested, and it extends it with a conditional # extra that will be installed whenever the condition matches and the # all extra is requested. - "all": ["genshi", "chardet>=2.2"], - "all:platform_python_implementation == 'CPython'": ["lxml"], + "all": ["genshi>=0.7.1", "chardet>=2.2.1"], + "all:platform_python_implementation == 'CPython'": ["lxml>=3.4.0"], }, ) diff --git a/tox.ini b/tox.ini index 42790f48..fb228e96 100644 --- a/tox.ini +++ b/tox.ini @@ -1,17 +1,18 @@ [tox] -envlist = py{27,35,36,37,38,39,310,311,py,py3}-{base,six19,optional} +envlist = py{27,35,36,37,38,39,310,311,py,py3}-{base,optional,oldest} [testenv] deps = + base: -r{toxinidir}/requirements-test.txt + optional: -r{toxinidir}/requirements-test.txt optional: -r{toxinidir}/requirements-optional.txt - -r{toxinidir}/requirements-test.txt + oldest: -r{toxinidir}/requirements-oldest.txt doc: Sphinx passenv = PYTEST_COMMAND # this is maintained so one can, e.g., PYTEST_COMMAND="coverage run -m pytest" COVERAGE_RUN_OPTIONS commands = - six19: pip install six==1.9 {env:PYTEST_COMMAND:{envbindir}/pytest} {posargs} flake8 {toxinidir} diff --git a/toxver.py b/toxver.py new file mode 100755 index 00000000..68eb71ec --- /dev/null +++ b/toxver.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +""" +usage: toxver.py [python-version] [deps] + +Returns a Tox environment name given a GHA matrix Python version and dependencies. +Many GHA configurations do this with inline Bash scripts but we want our solution +to be cross-platform and work on Windows workers, too. + +Examples: + + $ toxver.py pypy-3.8 base + TOXENV=pypy3-base + + $ toxver.py 2.7 oldest + TOXENV=py27-oldest + + $ toxver.py ~3.12.0-0 optional + TOXENV=py312-optional + +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import sys + + +def main(argv): + if len(argv) != 3: + print(__doc__.strip(), file=sys.stderr) + return 1 + + deps = argv[2] + + if argv[1].startswith("pypy-2"): + print("TOXENV=pypy-" + deps) + return 0 + + if argv[1].startswith("pypy-3"): + print("TOXENV=pypy3-" + deps) + return 0 + + if argv[1].startswith("~"): + ver = argv[1][1:5] + else: + ver = argv[1] + + ver = ver.replace(".", "") + print("TOXENV=py" + ver + "-" + deps) + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv))
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: