Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -276,10 +276,15 @@ jobs:
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: Check Formatting
if: matrix.check_formatting == '1'
run:
python -m pip install tox &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to use tox-uv too. Though, it's okay to omit. Especially in the initial effort.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure there's much, if any, speedup when we're only running a single environment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't compared them, but I'd imagine that provisioning that env would be faster. You don't separate the provisioning step in this PR, so I can't see how much it takes. But it's probably not important enough right now.

tox -m check
- name: Run tests
if: matrix.check_formatting == '0'
run: ./ci.sh
env:
CHECK_FORMATTING: '${{ matrix.check_formatting }}'
NO_TEST_REQUIREMENTS: '${{ matrix.no_test_requirements }}'
- if: >-
always()
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# generated by cythonize
tests/cython/test_cython.c

# In case somebody wants to restore the directory for local testing
notes-to-self/

81 changes: 0 additions & 81 deletions check.sh

This file was deleted.

190 changes: 92 additions & 98 deletions ci.sh
Original file line number Diff line number Diff line change
@@ -47,115 +47,109 @@ python -m build
wheel_package=$(ls dist/*.whl)
python -m uv pip install "trio @ $wheel_package" -c test-requirements.txt

if [ "$CHECK_FORMATTING" = "1" ]; then
python -m uv pip install -r test-requirements.txt exceptiongroup
echo "::endgroup::"
source check.sh
# Actual tests
# expands to 0 != 1 if NO_TEST_REQUIREMENTS is not set, if set the `-0` has no effect
# https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02
if [ "${NO_TEST_REQUIREMENTS-0}" == 1 ]; then
python -m uv pip install pytest coverage -c test-requirements.txt
flags="--skip-optional-imports"
else
# Actual tests
# expands to 0 != 1 if NO_TEST_REQUIREMENTS is not set, if set the `-0` has no effect
# https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02
if [ "${NO_TEST_REQUIREMENTS-0}" == 1 ]; then
python -m uv pip install pytest coverage -c test-requirements.txt
flags="--skip-optional-imports"
else
python -m uv pip install -r test-requirements.txt
flags=""
fi
python -m uv pip install -r test-requirements.txt
flags=""
fi

# So we can run the test for our apport/excepthook interaction working
if [ -e /etc/lsb-release ] && grep -q Ubuntu /etc/lsb-release; then
sudo apt install -q python3-apport
fi
# So we can run the test for our apport/excepthook interaction working
if [ -e /etc/lsb-release ] && grep -q Ubuntu /etc/lsb-release; then
sudo apt install -q python3-apport
fi

# If we're testing with a LSP installed, then it might break network
# stuff, so wait until after we've finished setting everything else
# up.
if [ "$LSP" != "" ]; then
echo "Installing LSP from ${LSP}"
# We use --insecure because one of the LSP's has been observed to give
# cert verification errors:
#
# https://github.com/python-trio/trio/issues/1478
#
# *Normally*, you should never ever use --insecure, especially when
# fetching an executable! But *in this case*, we're intentionally
# installing some untrustworthy quasi-malware onto into a sandboxed
# machine for testing. So MITM attacks are really the least of our
# worries.
if [ "$LSP_EXTRACT_FILE" != "" ]; then
# We host the Astrill VPN installer ourselves, and encrypt it
# so as to decrease the chances of becoming an inadvertent
# public redistributor.
curl-harder -o lsp-installer.zip "$LSP"
unzip -P "not very secret trio ci key" lsp-installer.zip "$LSP_EXTRACT_FILE"
mv "$LSP_EXTRACT_FILE" lsp-installer.exe
else
curl-harder --insecure -o lsp-installer.exe "$LSP"
fi
# This is only needed for the Astrill LSP, but there's no harm in
# doing it all the time. The cert was manually extracted by installing
# the package in a VM, clicking "Always trust from this publisher"
# when installing, and then running 'certmgr.msc' and exporting the
# certificate. See:
# http://www.migee.com/2010/09/24/solution-for-unattendedsilent-installs-and-would-you-like-to-install-this-device-software/
certutil -addstore "TrustedPublisher" src/trio/_tests/astrill-codesigning-cert.cer
# Double-slashes are how you tell windows-bash that you want a single
# slash, and don't treat this as a unix-style filename that needs to
# be replaced by a windows-style filename.
# http://www.mingw.org/wiki/Posix_path_conversion
./lsp-installer.exe //silent //norestart
echo "Waiting for LSP to appear in Winsock catalog"
while ! netsh winsock show catalog | grep "Layered Chain Entry"; do
sleep 1
done
netsh winsock show catalog
# If we're testing with a LSP installed, then it might break network
# stuff, so wait until after we've finished setting everything else
# up.
if [ "$LSP" != "" ]; then
echo "Installing LSP from ${LSP}"
# We use --insecure because one of the LSP's has been observed to give
# cert verification errors:
#
# https://github.com/python-trio/trio/issues/1478
#
# *Normally*, you should never ever use --insecure, especially when
# fetching an executable! But *in this case*, we're intentionally
# installing some untrustworthy quasi-malware onto into a sandboxed
# machine for testing. So MITM attacks are really the least of our
# worries.
if [ "$LSP_EXTRACT_FILE" != "" ]; then
# We host the Astrill VPN installer ourselves, and encrypt it
# so as to decrease the chances of becoming an inadvertent
# public redistributor.
curl-harder -o lsp-installer.zip "$LSP"
unzip -P "not very secret trio ci key" lsp-installer.zip "$LSP_EXTRACT_FILE"
mv "$LSP_EXTRACT_FILE" lsp-installer.exe
else
curl-harder --insecure -o lsp-installer.exe "$LSP"
fi
echo "::endgroup::"

echo "::group::Setup for tests"
# This is only needed for the Astrill LSP, but there's no harm in
# doing it all the time. The cert was manually extracted by installing
# the package in a VM, clicking "Always trust from this publisher"
# when installing, and then running 'certmgr.msc' and exporting the
# certificate. See:
# http://www.migee.com/2010/09/24/solution-for-unattendedsilent-installs-and-would-you-like-to-install-this-device-software/
certutil -addstore "TrustedPublisher" src/trio/_tests/astrill-codesigning-cert.cer
# Double-slashes are how you tell windows-bash that you want a single
# slash, and don't treat this as a unix-style filename that needs to
# be replaced by a windows-style filename.
# http://www.mingw.org/wiki/Posix_path_conversion
./lsp-installer.exe //silent //norestart
echo "Waiting for LSP to appear in Winsock catalog"
while ! netsh winsock show catalog | grep "Layered Chain Entry"; do
sleep 1
done
netsh winsock show catalog
fi
echo "::endgroup::"

# We run the tests from inside an empty directory, to make sure Python
# doesn't pick up any .py files from our working dir. Might have already
# been created by a previous run.
mkdir empty || true
cd empty
echo "::group::Setup for tests"

INSTALLDIR=$(python -c "import os, trio; print(os.path.dirname(trio.__file__))")
cp ../pyproject.toml "$INSTALLDIR" # TODO: remove this
# We run the tests from inside an empty directory, to make sure Python
# doesn't pick up any .py files from our working dir. Might have already
# been created by a previous run.
mkdir empty || true
cd empty

# get mypy tests a nice cache
MYPYPATH=".." mypy --config-file= --cache-dir=./.mypy_cache -c "import trio" >/dev/null 2>/dev/null || true
INSTALLDIR=$(python -c "import os, trio; print(os.path.dirname(trio.__file__))")
cp ../pyproject.toml "$INSTALLDIR" # TODO: remove this

# support subprocess spawning with coverage.py
echo "import coverage; coverage.process_startup()" | tee -a "$INSTALLDIR/../sitecustomize.py"
# get mypy tests a nice cache
MYPYPATH=".." mypy --config-file= --cache-dir=./.mypy_cache -c "import trio" >/dev/null 2>/dev/null || true

perl -i -pe 's/-p trio\._tests\.pytest_plugin//' "$INSTALLDIR/pyproject.toml"
# support subprocess spawning with coverage.py
echo "import coverage; coverage.process_startup()" | tee -a "$INSTALLDIR/../sitecustomize.py"

echo "::endgroup::"
echo "::group:: Run Tests"
if PYTHONPATH=../tests COVERAGE_PROCESS_START=$(pwd)/../pyproject.toml \
coverage run --rcfile=../pyproject.toml -m \
pytest -ra --junitxml=../test-results.xml \
-p _trio_check_attrs_aliases --verbose --durations=10 \
-p trio._tests.pytest_plugin --run-slow $flags "${INSTALLDIR}"; then
PASSED=true
else
PASSED=false
fi
echo "::endgroup::"
echo "::group::Coverage"
perl -i -pe 's/-p trio\._tests\.pytest_plugin//' "$INSTALLDIR/pyproject.toml"

coverage combine --rcfile ../pyproject.toml
coverage report -m --rcfile ../pyproject.toml
coverage xml --rcfile ../pyproject.toml
echo "::endgroup::"
echo "::group:: Run Tests"
if PYTHONPATH=../tests COVERAGE_PROCESS_START=$(pwd)/../pyproject.toml \
coverage run --rcfile=../pyproject.toml -m \
pytest -ra --junitxml=../test-results.xml \
-p _trio_check_attrs_aliases --verbose --durations=10 \
-p trio._tests.pytest_plugin --run-slow $flags "${INSTALLDIR}"; then
PASSED=true
else
PASSED=false
fi
echo "::endgroup::"
echo "::group::Coverage"

# Remove the LSP again; again we want to do this ASAP to avoid
# accidentally breaking other stuff.
if [ "$LSP" != "" ]; then
netsh winsock reset
fi
coverage combine --rcfile ../pyproject.toml
coverage report -m --rcfile ../pyproject.toml
coverage xml --rcfile ../pyproject.toml

echo "::endgroup::"
$PASSED
# Remove the LSP again; again we want to do this ASAP to avoid
# accidentally breaking other stuff.
if [ "$LSP" != "" ]; then
netsh winsock reset
fi

echo "::endgroup::"
$PASSED
106 changes: 106 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
[tox]
envlist = py{39,310,311,312,313,314,py310}
labels =
check = typing, gen_exports, type_completeness, pip_compile
cython = py39-cython2,py39-cython,py311-cython2,py313-cython

# TODO:
# * environment to check coverage
# * replace ci.sh
# * --verbose --durations=10
# * -p _trio_check_attrs_aliases
# * mypy cache
# * LSP
# * apport
# * use tox in CI
# * switch to nox?
# * move to pyproject.toml?
# * this means conditional deps need to be replaced

# protip: install uv-tox for faster venv generation

[testenv]
description = "Base environment for running tests depending on python version."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakkdl is configparser able to handle the quotes well? I think this is the first time I see them in this context.. Does the output of tox l look good?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...no 😅

❯ tox l
default environments:
py39 -> "Base environment for running tests depending on python version."
py310 -> "Base environment for running tests depending on python version."
py311 -> "Base environment for running tests depending on python version."
py312 -> "Base environment for running tests depending on python version."

# use wheels instead of sdist, significantly faster install
package = wheel
wheel_build_env = .pkg
deps =
hypothesis: hypothesis
-r test-requirements.txt
set_env =
slow: TOX_RUN_SLOW = '--run-slow'
commands =
pytest {env:TOX_RUN_SLOW:} {posargs}

[testenv:no_test_requirements]
description = "Run tests without optional test-requirements, to see we don't accidentally depend on a library not specified in depends."
deps =
pytest
commands =
pytest --skip-optional-imports {posargs}

[testenv:docs]
description = "Build documentation into docs/build."
deps =
-r docs-requirements.txt
# base_python synced with .readthedocs.yml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also make RTD just call tox in a follow-up. This is what I do these days.

# To avoid syncing we can make RTD call the tox environment
base_python = 3.11
commands =
sphinx-build {posargs:--fresh-env} docs/source docs/build

[testenv:py39-cython2,py39-cython,py311-cython2,py313-cython]
description = "Run cython tests."
deps =
cython
cython2: cython<3
setuptools ; python_version >= '3.12'
commands_pre =
python --version
cython --version
cythonize --inplace -X linetrace=True tests/cython/test_cython.pyx
commands =
python -m tests.cython.run_test_cython

[testenv:gen_exports]
description = "Run gen_exports.py, regenerating code for public API wrappers."
deps =
-r test-requirements.txt
base_python = 3.13
commands =
python ./src/trio/_tools/gen_exports.py --test

[testenv:pip_compile]
description = "Run pre-commit job pip-compile"
base_python = 3.13
commands =
pre-commit run pip-compile --all-files

# TODO: allow specifying e.g. typing-3.11 to run with --python[-]version=3.11
[testenv:typing]
description = "Run type checks: mypy on all platforms, and pyright on `src/trio[/_core]/_tests/type_tests/`."
deps =
-r test-requirements.txt
exceptiongroup
base_python = 3.13
set_env =
PYRIGHT_PYTHON_IGNORE_WARNINGS=1
commands =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add --python-version= in follow-ups.

Copy link
Member Author

@jakkdl jakkdl Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python versions are specified in pyproject.toml for both tools

edit: ah you mean parametrizing the version

# use mypy_annotate if running in CI? if not, should remove it
mypy --platform linux
mypy --platform darwin
mypy --platform win32
Comment on lines +90 to +92
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this use mypy_annotate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm. Maybe, but mypy_annotate is less needed with tox supressing output of succesful commands and in general reformatting the output. One of the problems with check.sh was simply finding what it was that failed, which I think is what prompted the creation of it. But we don't want it when running outside of CI, so needs some logic to differentiate.
But if we don't use it here then it should just be removed.

I'll procrastinate on it a little bit, and see what the output looks like in practice. I suspect the end result is going to be removing mypy_annotate


pyright src/trio/_tests/type_tests
pyright src/trio/_core/_tests/type_tests

[testenv:type_completeness]
description = "Check type completeness, using our wrapper around pyright --verifytypes."
deps =
-r test-requirements.txt
exceptiongroup
base_python = 3.13
set_env =
PYRIGHT_PYTHON_IGNORE_WARNINGS=1
commands =
python src/trio/_tests/check_type_completeness.py