diff --git a/.ci/build-manylinux-wheels.sh b/.ci/build-manylinux-wheels.sh deleted file mode 100755 index 7d1fcf0c..00000000 --- a/.ci/build-manylinux-wheels.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -set -e -x - -# Compile wheels -PYTHON="/opt/python/${PYTHON_VERSION}/bin/python" -PIP="/opt/python/${PYTHON_VERSION}/bin/pip" -${PIP} install -r /io/.ci/requirements.txt -make -C /io/ PYTHON="${PYTHON}" ci-clean compile -${PIP} wheel /io/ -w /io/dist/ - -# Bundle external shared libraries into the wheels. -for whl in /io/dist/*.whl; do - auditwheel repair --plat="manylinux2010_${PYARCH}" \ - $whl -w /io/dist/ - rm /io/dist/*-linux_*.whl -done - -PYTHON="/opt/python/${PYTHON_VERSION}/bin/python" -PIP="/opt/python/${PYTHON_VERSION}/bin/pip" -${PIP} install ${PYMODULE} --no-index -f file:///io/dist -rm -rf /io/tests/__pycache__ -make -C /io/ PYTHON="${PYTHON}" testinstalled -rm -rf /io/tests/__pycache__ diff --git a/.ci/package-version.py b/.ci/package-version.py deleted file mode 100755 index 83effeb9..00000000 --- a/.ci/package-version.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 - - -import os.path -import sys - - -def main(): - version_file = os.path.join( - os.path.dirname(os.path.dirname(__file__)), 'uvloop', '__init__.py') - - with open(version_file, 'r') as f: - for line in f: - if line.startswith('__version__ ='): - _, _, version = line.partition('=') - print(version.strip(" \n'\"")) - return 0 - - print('could not find package version in uvloop/__init__.py', - file=sys.stderr) - return 1 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/.ci/pypi-check.py b/.ci/pypi-check.py deleted file mode 100755 index 1b9c11c4..00000000 --- a/.ci/pypi-check.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 - - -import argparse -import sys -import xmlrpc.client - - -def main(): - parser = argparse.ArgumentParser(description='PyPI package checker') - parser.add_argument('package_name', metavar='PACKAGE-NAME') - - parser.add_argument( - '--pypi-index-url', - help=('PyPI index URL.'), - default='https://pypi.python.org/pypi') - - args = parser.parse_args() - - pypi = xmlrpc.client.ServerProxy(args.pypi_index_url) - releases = pypi.package_releases(args.package_name) - - if releases: - print(next(iter(sorted(releases, reverse=True)))) - - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/.ci/s3-download-release.py b/.ci/s3-download-release.py deleted file mode 100755 index 223f7f17..00000000 --- a/.ci/s3-download-release.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python3 - - -import argparse -import os -import os.path -import sys -import urllib.request - -import tinys3 - - -def main(): - parser = argparse.ArgumentParser(description='S3 File Uploader') - parser.add_argument( - '--s3-bucket', - help=('S3 bucket name (defaults to $S3_UPLOAD_BUCKET)'), - default=os.environ.get('S3_UPLOAD_BUCKET')) - parser.add_argument( - '--s3-region', - help=('S3 region (defaults to $S3_UPLOAD_REGION)'), - default=os.environ.get('S3_UPLOAD_REGION')) - parser.add_argument( - '--s3-username', - help=('S3 username (defaults to $S3_UPLOAD_USERNAME)'), - default=os.environ.get('S3_UPLOAD_USERNAME')) - parser.add_argument( - '--s3-key', - help=('S3 access key (defaults to $S3_UPLOAD_ACCESSKEY)'), - default=os.environ.get('S3_UPLOAD_ACCESSKEY')) - parser.add_argument( - '--s3-secret', - help=('S3 secret (defaults to $S3_UPLOAD_SECRET)'), - default=os.environ.get('S3_UPLOAD_SECRET')) - parser.add_argument( - '--destdir', - help='Destination directory.') - parser.add_argument( - 'package', metavar='PACKAGE', - help='Package name and version to download.') - - args = parser.parse_args() - - if args.s3_region: - endpoint = 's3-{}.amazonaws.com'.format(args.s3_region.lower()) - else: - endpoint = 's3.amazonaws.com' - - conn = tinys3.Connection( - access_key=args.s3_key, - secret_key=args.s3_secret, - default_bucket=args.s3_bucket, - tls=True, - endpoint=endpoint, - ) - - files = [] - - for entry in conn.list(args.package): - files.append(entry['key']) - - destdir = args.destdir or os.getpwd() - - for file in files: - print('Downloading {}...'.format(file)) - url = 'https://{}/{}/{}'.format(endpoint, args.s3_bucket, file) - target = os.path.join(destdir, file) - urllib.request.urlretrieve(url, target) - - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/.ci/s3-upload.py b/.ci/s3-upload.py deleted file mode 100755 index 92479afe..00000000 --- a/.ci/s3-upload.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 - - -import argparse -import glob -import os -import os.path -import sys - -import tinys3 - - -def main(): - parser = argparse.ArgumentParser(description='S3 File Uploader') - parser.add_argument( - '--s3-bucket', - help=('S3 bucket name (defaults to $S3_UPLOAD_BUCKET)'), - default=os.environ.get('S3_UPLOAD_BUCKET')) - parser.add_argument( - '--s3-region', - help=('S3 region (defaults to $S3_UPLOAD_REGION)'), - default=os.environ.get('S3_UPLOAD_REGION')) - parser.add_argument( - '--s3-username', - help=('S3 username (defaults to $S3_UPLOAD_USERNAME)'), - default=os.environ.get('S3_UPLOAD_USERNAME')) - parser.add_argument( - '--s3-key', - help=('S3 access key (defaults to $S3_UPLOAD_ACCESSKEY)'), - default=os.environ.get('S3_UPLOAD_ACCESSKEY')) - parser.add_argument( - '--s3-secret', - help=('S3 secret (defaults to $S3_UPLOAD_SECRET)'), - default=os.environ.get('S3_UPLOAD_SECRET')) - parser.add_argument( - 'files', nargs='+', metavar='FILE', help='Files to upload') - - args = parser.parse_args() - - if args.s3_region: - endpoint = 's3-{}.amazonaws.com'.format(args.s3_region.lower()) - else: - endpoint = 's3.amazonaws.com' - - conn = tinys3.Connection( - access_key=args.s3_key, - secret_key=args.s3_secret, - default_bucket=args.s3_bucket, - tls=True, - endpoint=endpoint, - ) - - for pattern in args.files: - for fn in glob.iglob(pattern): - with open(fn, 'rb') as f: - conn.upload(os.path.basename(fn), f) - - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/.ci/travis-build-wheels.sh b/.ci/travis-build-wheels.sh deleted file mode 100755 index a0d58292..00000000 --- a/.ci/travis-build-wheels.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -set -e -x - - -if [[ "${TRAVIS_BRANCH}" != "releases" || "${BUILD}" != *wheels* ]]; then - # Not a release - exit 0 -fi - - -if [ "${TRAVIS_OS_NAME}" == "osx" ]; then - PYENV_ROOT="$HOME/.pyenv" - PATH="$PYENV_ROOT/bin:$PATH" - eval "$(pyenv init -)" - pyenv local ${PYTHON_VERSION} -fi - -PACKAGE_VERSION=$(python ".ci/package-version.py") -PYPI_VERSION=$(python ".ci/pypi-check.py" "${PYMODULE}") - -if [ "${PACKAGE_VERSION}" == "${PYPI_VERSION}" ]; then - echo "${PYMODULE}-${PACKAGE_VERSION} is already published on PyPI" - exit 1 -fi - - -pushd $(dirname $0) > /dev/null -_root=$(dirname $(pwd -P)) -popd > /dev/null - - -_upload_wheels() { - python "${_root}/.ci/s3-upload.py" "${_root}/dist"/*.whl - sudo rm -rf "${_root}/dist"/*.whl -} - - -if [ "${TRAVIS_OS_NAME}" == "linux" ]; then - for pyver in ${RELEASE_PYTHON_VERSIONS}; do - ML_PYTHON_VERSION=$(python3 -c \ - "print('cp{maj}{min}-cp{maj}{min}{s}'.format( \ - maj='${pyver}'.split('.')[0], \ - min='${pyver}'.split('.')[1], - s='m' if tuple('${pyver}'.split('.')) < ('3', '8') \ - else ''))") - - for arch in x86_64; do - ML_IMAGE="quay.io/pypa/manylinux2010_${arch}" - docker pull "${ML_IMAGE}" - docker run --rm \ - -v "${_root}":/io \ - -e "PYARCH=${arch}" \ - -e "PYMODULE=${PYMODULE}" \ - -e "PYTHON_VERSION=${ML_PYTHON_VERSION}" \ - "${ML_IMAGE}" /io/.ci/build-manylinux-wheels.sh - - _upload_wheels - done - done - -elif [ "${TRAVIS_OS_NAME}" == "osx" ]; then - make clean && make -C "${_root}" - pip wheel "${_root}" -w "${_root}/dist/" - - pip install ${PYMODULE} --no-index -f "file:///${_root}/dist" - pushd / >/dev/null - make -C "${_root}" testinstalled - popd >/dev/null - - _upload_wheels - -else - echo "Cannot build on ${TRAVIS_OS_NAME}." -fi diff --git a/.ci/travis-install.sh b/.ci/travis-install.sh deleted file mode 100755 index 626129a7..00000000 --- a/.ci/travis-install.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -set -e -x - -if [ "${TRAVIS_OS_NAME}" == "osx" ]; then - # Travis xcode7.3 image is still using deprecated homebrew/versions - # https://docs.brew.sh/Versions - brew untap homebrew/versions - brew update >/dev/null - brew upgrade pyenv - eval "$(pyenv init -)" - - if ! (pyenv versions | grep "${PYTHON_VERSION}$"); then - pyenv install ${PYTHON_VERSION} - fi - pyenv global ${PYTHON_VERSION} - pyenv rehash - - brew install gnu-sed - brew outdated libtool || brew upgrade libtool - brew outdated autoconf || brew upgrade autoconf - brew outdated automake || brew upgrade automake -fi - -pip install --upgrade setuptools pip wheel -pip install -r .ci/requirements.txt diff --git a/.ci/travis-release.sh b/.ci/travis-release.sh deleted file mode 100755 index 8932b4e6..00000000 --- a/.ci/travis-release.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -set -e -x - - -if [ -z "${TRAVIS_TAG}" ]; then - # Not a release - exit 0 -fi - - -PACKAGE_VERSION=$(python ".ci/package-version.py") -PYPI_VERSION=$(python ".ci/pypi-check.py" "${PYMODULE}") - -if [ "${PACKAGE_VERSION}" == "${PYPI_VERSION}" ]; then - echo "${PYMODULE}-${PACKAGE_VERSION} is already published on PyPI" - exit 0 -fi - -# Check if all expected wheels have been built and uploaded. -release_platforms=( - "macosx_10_??_x86_64" - "manylinux*_x86_64" -) - -P="${PYMODULE}-${PACKAGE_VERSION}" -expected_wheels=() - -for pyver in ${RELEASE_PYTHON_VERSIONS}; do - abitag=$(python -c \ - "print('cp{maj}{min}-cp{maj}{min}{s}'.format( \ - maj='${pyver}'.split('.')[0], \ - min='${pyver}'.split('.')[1], - s='m' if tuple('${pyver}'.split('.')) < ('3', '8') else ''))") - for plat in "${release_platforms[@]}"; do - expected_wheels+=("${P}-${abitag}-${plat}.whl") - done -done - -rm -rf dist/*.whl dist/*.tar.* -python setup.py sdist -python ".ci/s3-download-release.py" --destdir=dist/ "${P}" - -_file_exists() { [[ -f $1 ]]; } - -for distfile in "${expected_wheels[@]}"; do - if ! _file_exists dist/${distfile}; then - echo "Expected wheel ${distfile} not found." - exit 1 - fi -done - -python -m twine upload dist/*.whl dist/*.tar.* diff --git a/.ci/travis-tests.sh b/.ci/travis-tests.sh deleted file mode 100755 index 0fc4aa23..00000000 --- a/.ci/travis-tests.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e -x - -if [[ "${BUILD}" != *tests* ]]; then - echo "Skipping tests." - exit 0 -fi - -if [ "${TRAVIS_OS_NAME}" == "osx" ]; then - PYENV_ROOT="$HOME/.pyenv" - PATH="$PYENV_ROOT/bin:$PATH" - eval "$(pyenv init -)" -fi - -make distclean && make && make test -make distclean && make debug && make test diff --git a/.ci/requirements.txt b/.github/workflows/test-requirements.txt similarity index 82% rename from .ci/requirements.txt rename to .github/workflows/test-requirements.txt index 6bb3d4ce..fc9e8e82 100644 --- a/.ci/requirements.txt +++ b/.github/workflows/test-requirements.txt @@ -1,7 +1,5 @@ Cython==0.29.13 aiohttp -tinys3 -twine psutil pyOpenSSL==19.0.0 flake8>=3.7.5 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..991c15a5 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,63 @@ +name: Tests + +on: + push: + branches: + - master + - ci + pull_request: + branches: + - master + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8, 3.9] + os: [ubuntu-latest, macos-latest] + + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 50 + submodules: true + + - name: Check if release PR. + uses: edgedb/action-release/validate-pr@master + continue-on-error: true + id: release + with: + github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }} + version_file: uvloop/_version.py + version_line_pattern: | + __version__\s*=\s*(?:['"])([[:PEP440:]])(?:['"]) + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + if: steps.release.outputs.version == 0 + with: + python-version: ${{ matrix.python-version }} + + - name: Install macOS deps + if: matrix.os == 'macos-latest' && steps.release.outputs.version == 0 + run: | + brew install gnu-sed libtool autoconf automake + + - uses: syphar/restore-virtualenv@v1 + if: steps.release.outputs.version == 0 + id: cache-virtualenv + with: + requirement_files: .github/workflows/test-requirements.txt + + - name: Install Python Deps + if: steps.release.outputs.version == 0 && steps.cache-virtualenv.outputs.cache-hit != 'true' + run: | + pip install --upgrade setuptools pip wheel + pip install -U -r .github/workflows/test-requirements.txt + + - name: Test + if: steps.release.outputs.version == 0 + run: | + make distclean && make && make test + make distclean && make debug && make test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 56a8d432..00000000 --- a/.travis.yml +++ /dev/null @@ -1,99 +0,0 @@ -language: generic - -env: - global: - - PYMODULE=uvloop - - RELEASE_PYTHON_VERSIONS="3.5 3.6 3.7 3.8" - - - S3_UPLOAD_USERNAME=oss-ci-bot - - S3_UPLOAD_BUCKET=magicstack-oss-releases - # S3_UPLOAD_ACCESSKEY: - - secure: "g3fR9aJe2+BvQt8xR2RHLJsrOhxxEmz2RHRDY1Sy5bFTMFA3CYtj8ylTxvFADotFWd8Q81xV7Q450hD6eOLlIP/twsibvhbzXmOybswzFJnLaOrciUQE2iCQ6AzmkPBut3BNpAtdXPlbmJoHntKSZWu6Dt/UvQ2w23hGlp9EW1JtOV3jE2m/FdCcfDYxa/tZPJ7cnQKuMXo5N4/Es2IPyIurTpqbgYo3K2UnX1nSNcAdBPzigC/H0zJpLerXeqhNWeXimhFH6QAMsk7JvVGMYWfxq2lVBKpM7v8JRd9wk1ux8VNJNWDjLUVcskgmF+KwmbPdn1xx3bwy+FZBuH4WCjSepNAdyUgOF6y9YgdZ1kpQcfhVUIQEgH/5nFOA81oABMlCJ+eHSt+jxJoo69g82lHyVxcfKm34mG380tOJK+R6ZDIi+2Qsvoi86TCxiju6ecCu3fx/0JEiT8cDwMo7KedhSN7d+NiZRJ5xB40FXk0zTf6WfDmgD7twjnCwhCXKU4U8eVi0pVMSUqjP3sPkFPa+licg7irjgt7dmpLJhqZb2JZt78HcrANiLyfoFWhOB7TYfPbP8Fv+g/rs8y/Q+oOBcJnFV2YkltB+sLFvv9jQlP1z6NBSvJZl0IUuC3vNt6b1aMuesXbPQntqXBkL1Vu7WQTmo4LmKwvdGze/0sY=" - # S3_UPLOAD_SECRET: - - secure: "M0NfG4tJryVEe+6IXfAtrRe08PMd6VfyOj7NQPOEX4WqaSvWjROSA7WIVrawh64TR9hcjnQT2gflU9jA2r2z0/vUYyQ5M2gU3TXoSD+uRH7I/BdUxKQvAWCd/y+JYwMHg1yY+/WClSnvwFw0F4MIzOzTyVVEbF0K2T+azN2pxNx6KIOmZQOY3yLA0MwUbD78EKuyOWdIhizTA0XUSHqH1RTdZVmXdn8hz7RePe8jdivaHY6gRMPzeunh7w+Sl64Nu9nWDdy/Iu9yyLzmLWDpQMzSzaHLbTKCu13YDMWiAOp0hO5WWSfXpYSyJ6EcAAk+RTKXQQVZkie8/a/0nrhdvrhxWjG9hwrSad7L8baYdWFmcnWlvTp2gizFO1c2G8jomRhkr+M9TF2Z6J6+oJPzHLFlFOpy71I+O4sWQqCgfp+oNX0HfcOF6KY2HuWrUCcne1drgFgOkH2vg5OOhjLSB21N+UnbkOqWm9K6xa9b2feNdqhjZxij1RbA/7WlsZ15mgjnIhEc0juI2TcylxX09ASg1udGlj7Oqr9eZn+Xg7ScPb4SQnTr0hPfFWBAW7AeZbSx4FkZXDYZXWa5U517Q6TgUi1FFF843unP9mNMZC7WpQGcuLhW2iLHDjvSwczKvEjdRYEqeDCTShG89MVMsrqHDui4EzQI5DrlV/aJxcE=" - - - TWINE_USERNAME: magicstack-ci - # TWINE_PASSWORD: - - secure: "MhkWx5Z2KIVp9VGNiiMrJAbfiNeuHt5uZLsnFvSWqmi66MnBt15uRfle/9swNpc2eaNJ7XcC3oVvo6pf2118gyXxdqfgOCApLIjW4uBJwwzpA2DrCVxXT6gNVaDZ5c1PgHAAwY/jMxbloRPneqtyD6Pt5FvqcKy/VSp5DEEea+nJqX7MEk0I3ZtkvCxu6kBJ4wEfSyxilBVrezydEyimjUrHECyaSI92MLy6LRGZxOjM+Y++bjtnU3cYxXhu0W/E1CYQLUF1ZdhgAKNNcsQz939KuNrT5iVUNU2iDi+TKufG1seekaaoetSfhKmL94Bf1m/Yux+AyoUgoOA18sioqDbDW4zXQTTLnyFXTMQGXzKiYE7SXwOqteLNfzs90tHDwkyvVOSDvkh3uxFIz/pDkiBGp1/o1w9JncPlmKxreXMyBDJSbDomKptr3aswU31l3KOlOBO2uCQuzFtJc4Act+gV7MTxgVBKmIbxZaSUpE8elBVcNUTIruMaCvieYfDk/GgX1619bE8k2SR/z/gQ1OB5fmb/daN8/cqAw1r9PWsIRlvOkhrONIACkjvoZDErMo9DyDI2AqLKGhk6/QUwwatD9NIZe7nnEeEsJsoI7o4T+gJPGta0owU4XaAB+JY0VZ6gsun3+hY8cAhnhNYF3TDtiSL73c70vf55+LYaM/E=" - -branches: - # Avoid building PR branches. - only: - - master - - ci - - releases - - /^v\d+(\.\d+)*(rc\d+)?$/ - -matrix: - fast_finish: true - - include: - - os: osx - osx_image: xcode7.3 - # Travis macOS env does not support Python yet, - # so we have to set things up manually in install.sh. - env: BUILD=tests,wheels PYTHON_VERSION=3.5.5 - branches: {only: [releases]} - - - os: osx - osx_image: xcode7.3 - env: BUILD=tests,wheels PYTHON_VERSION=3.6.5 - branches: {only: [releases]} - - - os: osx - osx_image: xcode7.3 - env: BUILD=tests,wheels PYTHON_VERSION=3.7.0 - branches: {only: [releases]} - - - os: osx - osx_image: xcode7.3 - env: BUILD=tests,wheels PYTHON_VERSION=3.8.0 - branches: {only: [releases]} - - - os: linux - dist: trusty - language: python - python: "3.5" - env: BUILD=tests - - - os: linux - dist: trusty - language: python - python: "3.6" - env: BUILD=tests - - - os: linux - dist: xenial - language: python - python: "3.7" - env: BUILD=tests - - - os: linux - dist: xenial - language: python - python: "3.8" - env: BUILD=tests - - - os: linux - dist: trusty - branches: {only: [releases]} - language: python - python: "3.5" - services: [docker] - env: BUILD=tests,wheels,release - -cache: - pip - -install: - - .ci/travis-install.sh - -script: - - .ci/travis-tests.sh && .ci/travis-build-wheels.sh - -deploy: - provider: script - script: .ci/travis-release.sh - on: - tags: true - condition: '"${BUILD}" == *release*' diff --git a/setup.py b/setup.py index 46b512ee..ea95bc19 100644 --- a/setup.py +++ b/setup.py @@ -220,7 +220,7 @@ def build_extensions(self): with open(os.path.join( - os.path.dirname(__file__), 'uvloop', '__init__.py')) as f: + os.path.dirname(__file__), 'uvloop', '_version.py')) as f: for line in f: if line.startswith('__version__ ='): _, _, version = line.partition('=') @@ -228,7 +228,7 @@ def build_extensions(self): break else: raise RuntimeError( - 'unable to read the version from uvloop/__init__.py') + 'unable to read the version from uvloop/_version.py') setup( diff --git a/tests/test_base.py b/tests/test_base.py index 512b0d7a..125bd7d4 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -159,7 +159,7 @@ def cb(inc=10, stop=False): self.assertEqual(calls, [10, 1]) self.assertFalse(self.loop.is_running()) - self.assertLess(finished - started, 0.1) + self.assertLess(finished - started, 0.2) self.assertGreater(finished - started, 0.04) def test_call_later_2(self): @@ -219,9 +219,10 @@ def cb(): self.assertGreaterEqual(finished - started, 69) def test_call_at(self): - if os.environ.get('TRAVIS_OS_NAME'): + if (os.environ.get('TRAVIS_OS_NAME') + or os.environ.get('GITHUB_WORKFLOW')): # Time seems to be really unpredictable on Travis. - raise unittest.SkipTest('time is not monotonic on Travis') + raise unittest.SkipTest('time is not monotonic on CI') i = 0 @@ -635,9 +636,9 @@ def test_shutdown_asyncgens_02(self): def logger(loop, context): nonlocal logged - self.assertIn('asyncgen', context) expected = 'an error occurred during closing of asynchronous' if expected in context['message']: + self.assertIn('asyncgen', context) logged += 1 waiter = self._compile_agen('''async def waiter(timeout): diff --git a/tests/test_process.py b/tests/test_process.py index aa7def56..e1eb6cc3 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -840,7 +840,9 @@ def test_process_delayed_stdio__paused__no_stdin(self): }) def test_process_delayed_stdio__not_paused__no_stdin(self): - if os.environ.get('TRAVIS_OS_NAME') and sys.platform == 'darwin': + if ((os.environ.get('TRAVIS_OS_NAME') + or os.environ.get('GITHUB_WORKFLOW')) + and sys.platform == 'darwin'): # Randomly crashes on Travis, can't reproduce locally. raise unittest.SkipTest() diff --git a/tests/test_process_spawning.py b/tests/test_process_spawning.py index ba556695..71fe914d 100644 --- a/tests/test_process_spawning.py +++ b/tests/test_process_spawning.py @@ -20,7 +20,10 @@ async def run(loop): dummy_workers = [simulate_loop_activity(loop, event) for _ in range(5)] spawn_worker = spawn_external_process(loop, event) - done, pending = await asyncio.wait([spawn_worker] + dummy_workers) + done, pending = await asyncio.wait([ + asyncio.ensure_future(fut) + for fut in ([spawn_worker] + dummy_workers) + ]) exceptions = [result.exception() for result in done if result.exception()] if exceptions: diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 3c1f7a38..7d87571e 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -195,8 +195,8 @@ def test_socket_sync_remove_and_immediately_close(self): def test_sock_cancel_add_reader_race(self): if self.is_asyncio_loop(): - if (3, 8, 2) >= sys.version_info[:3] >= (3, 8, 0): - # asyncio 3.8.0 seems to have a regression; + if sys.version_info[:2] == (3, 8): + # asyncio 3.8.x has a regression; fixed in 3.9.0 # tracked in https://bugs.python.org/issue30064 raise unittest.SkipTest() @@ -223,8 +223,13 @@ async def client(addr): with sock_client: await self.loop.sock_connect(sock_client, addr) _, pending_read_futs = await asyncio.wait( - [self.loop.sock_recv(sock_client, 1)], - timeout=1) + [ + asyncio.ensure_future( + self.loop.sock_recv(sock_client, 1) + ) + ], + timeout=1, + ) async def send_server_data(): # Wait a little bit to let reader future cancel and @@ -273,8 +278,13 @@ async def client(addr): with sock_client: await self.loop.sock_connect(sock_client, addr) _, pending_read_futs = await asyncio.wait( - [self.loop.sock_recv(sock_client, 1)], - timeout=1) + [ + asyncio.ensure_future( + self.loop.sock_recv(sock_client, 1) + ) + ], + timeout=1, + ) # server can send the data in a random time, even before # the previous result future has cancelled. diff --git a/tests/test_tcp.py b/tests/test_tcp.py index 83a61a2f..26b53d8b 100644 --- a/tests/test_tcp.py +++ b/tests/test_tcp.py @@ -2526,8 +2526,13 @@ def unwrap_server(sock): except ssl.SSLError as ex: # Since OpenSSL 1.1.1, it raises "application data after # close notify" + # Python < 3.8: if ex.reason == 'KRB5_S_INIT': break + # Python >= 3.8: + if ex.reason == 'APPLICATION_DATA_AFTER_CLOSE_NOTIFY': + break + raise ex except OSError as ex: # OpenSSL < 1.1.1 if ex.errno != 0: diff --git a/tests/test_udp.py b/tests/test_udp.py index a7474965..d5e0c17e 100644 --- a/tests/test_udp.py +++ b/tests/test_udp.py @@ -308,7 +308,7 @@ def datagram_received(self, data, addr): s2.send(b'hello, socketpair') addr = self.loop.run_until_complete( - asyncio.wait_for(peername, 1, loop=self.loop)) + asyncio.wait_for(peername, 1)) if sys.platform.startswith('linux'): self.assertEqual(addr, None) else: @@ -322,7 +322,7 @@ def datagram_received(self, data, addr): tr.sendto(data) result = self.loop.run_until_complete(asyncio.wait_for( self.loop.run_in_executor(None, s2.recv, 1024), - 1, loop=self.loop)) + 1)) self.assertEqual(data, result) tr.close() diff --git a/uvloop/__init__.py b/uvloop/__init__.py index 9d98c6f1..6dec2ba5 100644 --- a/uvloop/__init__.py +++ b/uvloop/__init__.py @@ -5,9 +5,9 @@ from . import includes as __includes # NOQA from . import _patch # NOQA from .loop import Loop as __BaseLoop # NOQA +from ._version import __version__ # NOQA -__version__ = '0.15.0.dev0' __all__ = ('new_event_loop', 'install', 'EventLoopPolicy') diff --git a/uvloop/_version.py b/uvloop/_version.py new file mode 100644 index 00000000..07c152a4 --- /dev/null +++ b/uvloop/_version.py @@ -0,0 +1,13 @@ +# This file MUST NOT contain anything but the __version__ assignment. +# +# When making a release, change the value of __version__ +# to an appropriate value, and open a pull request against +# the correct branch (master if making a new feature release). +# The commit message MUST contain a properly formatted release +# log, and the commit must be signed. +# +# The release automation will: build and test the packages for the +# supported platforms, publish the packages on PyPI, merge the PR +# to the target branch, create a Git tag pointing to the commit. + +__version__ = '0.15.0.dev0' diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index b576eabe..fa68ca5b 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -48,6 +48,7 @@ include "includes/stdlib.pxi" include "errors.pyx" cdef: + int PY39 = PY_VERSION_HEX >= 0x03090000 int PY37 = PY_VERSION_HEX >= 0x03070000 int PY36 = PY_VERSION_HEX >= 0x03060000 uint64_t MAX_SLEEP = 3600 * 24 * 365 * 100 @@ -3190,12 +3191,20 @@ class _SyncSocketReaderFuture(aio_Future): self.__sock = sock self.__loop = loop - def cancel(self): + def __remove_reader(self): if self.__sock is not None and self.__sock.fileno() != -1: self.__loop.remove_reader(self.__sock) self.__sock = None - aio_Future.cancel(self) + if PY39: + def cancel(self, msg=None): + self.__remove_reader() + aio_Future.cancel(self, msg=msg) + + else: + def cancel(self): + self.__remove_reader() + aio_Future.cancel(self) class _SyncSocketWriterFuture(aio_Future): @@ -3205,12 +3214,20 @@ class _SyncSocketWriterFuture(aio_Future): self.__sock = sock self.__loop = loop - def cancel(self): + def __remove_writer(self): if self.__sock is not None and self.__sock.fileno() != -1: self.__loop.remove_writer(self.__sock) self.__sock = None - aio_Future.cancel(self) + if PY39: + def cancel(self, msg=None): + self.__remove_writer() + aio_Future.cancel(self, msg=msg) + + else: + def cancel(self): + self.__remove_writer() + aio_Future.cancel(self) include "cbhandles.pyx"