MOTOR-1139 Switch to Pytest (#222)
This commit is contained in:
parent
70136ad1f2
commit
f905df8553
@ -403,9 +403,6 @@ functions:
|
|||||||
set -x
|
set -x
|
||||||
export LIBMONGOCRYPT_URL="${libmongocrypt_url}"
|
export LIBMONGOCRYPT_URL="${libmongocrypt_url}"
|
||||||
export TEST_ENCRYPTION=1
|
export TEST_ENCRYPTION=1
|
||||||
if [ -n "${EXTRA_PATH}" ]; then
|
|
||||||
export PATH="${EXTRA_PATH}:$PATH"
|
|
||||||
fi
|
|
||||||
PYTHON_BINARY="${PYTHON_BINARY}" \
|
PYTHON_BINARY="${PYTHON_BINARY}" \
|
||||||
TOX_BINARY="${TOX_BINARY}" \
|
TOX_BINARY="${TOX_BINARY}" \
|
||||||
TOX_ENV="${TOX_ENV}" \
|
TOX_ENV="${TOX_ENV}" \
|
||||||
@ -424,7 +421,6 @@ functions:
|
|||||||
working_dir: "src"
|
working_dir: "src"
|
||||||
script: |
|
script: |
|
||||||
# DO NOT ECHO WITH XTRACE (which PREPARE_SHELL does)
|
# DO NOT ECHO WITH XTRACE (which PREPARE_SHELL does)
|
||||||
|
|
||||||
CLIENT_PEM=${DRIVERS_TOOLS}/.evergreen/x509gen/client.pem \
|
CLIENT_PEM=${DRIVERS_TOOLS}/.evergreen/x509gen/client.pem \
|
||||||
CA_PEM=${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem \
|
CA_PEM=${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem \
|
||||||
PYTHON_BINARY=${PYTHON_BINARY} \
|
PYTHON_BINARY=${PYTHON_BINARY} \
|
||||||
@ -799,7 +795,7 @@ tasks:
|
|||||||
commands:
|
commands:
|
||||||
- func: "run tox"
|
- func: "run tox"
|
||||||
vars:
|
vars:
|
||||||
TOX_ENV: py3-sphinx-docs
|
TOX_ENV: docs
|
||||||
|
|
||||||
- name: "doctest"
|
- name: "doctest"
|
||||||
commands:
|
commands:
|
||||||
@ -809,7 +805,7 @@ tasks:
|
|||||||
TOPOLOGY: "server"
|
TOPOLOGY: "server"
|
||||||
- func: "run tox"
|
- func: "run tox"
|
||||||
vars:
|
vars:
|
||||||
TOX_ENV: py3-sphinx-doctest
|
TOX_ENV: doctest
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
@ -831,127 +827,95 @@ axes:
|
|||||||
- id: tox-env
|
- id: tox-env
|
||||||
display_name: "Tox Env RHEL8"
|
display_name: "Tox Env RHEL8"
|
||||||
values:
|
values:
|
||||||
- id: "tornado5-pypy37"
|
- id: "test-pypy38"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado5-pypy37"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/pypy3.7/bin/pypy3"
|
PYTHON_BINARY: "/opt/python/pypy3.8/bin/python3"
|
||||||
- id: "tornado5-py37"
|
- id: "test-py37"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado5-py37"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
||||||
- id: "tornado6-pypy37"
|
- id: "test-py37"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6-pypy37"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/pypy3.7/bin/pypy3"
|
|
||||||
- id: "tornado6-py37"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "tornado6-py37"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
||||||
- id: "tornado6-py38"
|
- id: "test-py38"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6-py38"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
||||||
- id: "tornado6-py39"
|
- id: "test-py39"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6-py39"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
|
||||||
- id: "tornado6-py310"
|
- id: "test-py310"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6-py310"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||||
- id: "tornado6-py311"
|
- id: "test-py311"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6-py311"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/3.11/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.11/bin/python3"
|
||||||
- id: "tornado6-py312"
|
- id: "test-py312"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6-py312"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/3.12/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.12/bin/python3"
|
||||||
- id: "tornado_git-py38"
|
- id: "test-pymongo-latest"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado_git-py38"
|
TOX_ENV: "test-pymongo-latest"
|
||||||
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
|
||||||
- id: "asyncio-pypy37"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "asyncio-pypy37"
|
|
||||||
PYTHON_BINARY: "/opt/python/pypy3.7/bin/pypy3"
|
|
||||||
- id: "asyncio-py37"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "asyncio-py37"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
||||||
- id: "asyncio-py38"
|
- id: "synchro-py37"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "asyncio-py38"
|
TOX_ENV: "synchro"
|
||||||
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
|
||||||
- id: "asyncio-py39"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "asyncio-py39"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
|
|
||||||
- id: "asyncio-py310"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "asyncio-py310"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
|
||||||
- id: "asyncio-py311"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "asyncio-py311"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.11/bin/python3"
|
|
||||||
- id: "asyncio-py312"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "asyncio-py312"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.12/bin/python3"
|
|
||||||
- id: "py3-pymongo-latest"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "py3-pymongo-latest"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
|
||||||
- id: "synchro37"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "synchro37"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
||||||
- id: "synchro312"
|
- id: "synchro-py312"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "synchro312"
|
TOX_ENV: "synchro"
|
||||||
PYTHON_BINARY: "/opt/python/3.12/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.12/bin/python3"
|
||||||
|
|
||||||
- id: tox-env-rhel7
|
- id: tox-env-rhel7
|
||||||
display_name: "Tox Env RHEL7"
|
display_name: "Tox Env RHEL7"
|
||||||
values:
|
values:
|
||||||
- id: "tornado6-py39"
|
- id: "test"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6-py39"
|
TOX_ENV: "test"
|
||||||
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
|
|
||||||
- id: "asyncio-py39"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "asyncio-py39"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
|
||||||
|
|
||||||
# Test Python 3.8 only on Mac.
|
# Test Python 3.8 only on Mac.
|
||||||
- id: tox-env-osx
|
- id: tox-env-osx
|
||||||
display_name: "Tox Env OSX"
|
display_name: "Tox Env OSX"
|
||||||
values:
|
values:
|
||||||
- id: "tornado5"
|
- id: "test"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado5"
|
TOX_ENV: "test"
|
||||||
EXTRA_PATH: "/Library/Frameworks/Python.framework/Versions/3.8/bin/"
|
PYTHON_BINARY: "/Library/Frameworks/Python.framework/Versions/3.8/bin/python3"
|
||||||
- id: "tornado_git"
|
|
||||||
variables:
|
|
||||||
TOX_ENV: "tornado_git"
|
|
||||||
EXTRA_PATH: "/Library/Frameworks/Python.framework/Versions/3.8/bin/"
|
|
||||||
|
|
||||||
- id: tox-env-win
|
- id: tox-env-win
|
||||||
display_name: "Tox Env Windows"
|
display_name: "Tox Env Windows"
|
||||||
values:
|
values:
|
||||||
- id: "asyncio"
|
- id: "test-py37"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "asyncio"
|
TOX_ENV: "test"
|
||||||
EXTRA_PATH: "c:\\python\\Python37"
|
PYTHON_BINARY: "c:/python/Python37/python.exe"
|
||||||
- id: "tornado6"
|
- id: "test-py38"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6"
|
TOX_ENV: "test"
|
||||||
EXTRA_PATH: "c:\\python\\Python37"
|
PYTHON_BINARY: "c:/python/Python39/python.exe"
|
||||||
- id: "tornado6"
|
- id: "test-py39"
|
||||||
variables:
|
variables:
|
||||||
TOX_ENV: "tornado6"
|
TOX_ENV: "test"
|
||||||
EXTRA_PATH: "c:\\python\\Python38"
|
PYTHON_BINARY: "c:/python/Python39/python.exe"
|
||||||
|
- id: "test-py310"
|
||||||
|
variables:
|
||||||
|
TOX_ENV: "test"
|
||||||
|
PYTHON_BINARY: "c:/python/Python310/python.exe"
|
||||||
|
- id: "test-py311"
|
||||||
|
variables:
|
||||||
|
TOX_ENV: "test"
|
||||||
|
PYTHON_BINARY: "c:/python/Python311/python.exe"
|
||||||
|
- id: "test-py312"
|
||||||
|
variables:
|
||||||
|
TOX_ENV: "test"
|
||||||
|
PYTHON_BINARY: "c:/python/Python312/python.exe"
|
||||||
|
|
||||||
- id: os
|
- id: os
|
||||||
display_name: "Operating System"
|
display_name: "Operating System"
|
||||||
@ -959,27 +923,15 @@ axes:
|
|||||||
- id: "rhel84"
|
- id: "rhel84"
|
||||||
display_name: "RHEL 8.4"
|
display_name: "RHEL 8.4"
|
||||||
run_on: "rhel84-small"
|
run_on: "rhel84-small"
|
||||||
variables:
|
|
||||||
INSTALL_TOX: true
|
|
||||||
VIRTUALENV: "/opt/python/3.7/bin/python3 -m virtualenv"
|
|
||||||
- id: "rhel76"
|
- id: "rhel76"
|
||||||
display_name: "RHEL 7.6"
|
display_name: "RHEL 7.6"
|
||||||
run_on: "rhel76-small"
|
run_on: "rhel76-small"
|
||||||
variables:
|
|
||||||
INSTALL_TOX: true
|
|
||||||
VIRTUALENV: "/opt/python/3.7/bin/python3 -m virtualenv"
|
|
||||||
- id: "win"
|
- id: "win"
|
||||||
display_name: "Windows"
|
display_name: "Windows"
|
||||||
run_on: "windows-64-vsMulti-small"
|
run_on: "windows-64-vsMulti-small"
|
||||||
variables:
|
|
||||||
INSTALL_TOX: true
|
|
||||||
VIRTUALENV: "/cygdrive/c/python/Python37/python.exe -m virtualenv"
|
|
||||||
- id: "macos-1100"
|
- id: "macos-1100"
|
||||||
display_name: "macOS 11.00"
|
display_name: "macOS 11.00"
|
||||||
run_on: "macos-1100"
|
run_on: "macos-1100"
|
||||||
variables:
|
|
||||||
INSTALL_TOX: true
|
|
||||||
VIRTUALENV: "/Library/Frameworks/Python.framework/Versions/3.8/bin/python3 -m venv"
|
|
||||||
|
|
||||||
buildvariants:
|
buildvariants:
|
||||||
|
|
||||||
@ -994,7 +946,7 @@ buildvariants:
|
|||||||
# TODO: synchro needs PyMongo's updated SSL test certs,
|
# TODO: synchro needs PyMongo's updated SSL test certs,
|
||||||
# which may require Motor test suite changes.
|
# which may require Motor test suite changes.
|
||||||
- os: "*"
|
- os: "*"
|
||||||
tox-env: ["synchro37", "synchro312"]
|
tox-env: ["synchro-py37", "synchro-py312"]
|
||||||
ssl: "ssl"
|
ssl: "ssl"
|
||||||
tasks:
|
tasks:
|
||||||
- ".rapid"
|
- ".rapid"
|
||||||
@ -1052,7 +1004,7 @@ buildvariants:
|
|||||||
|
|
||||||
- matrix_name: "enterprise-auth"
|
- matrix_name: "enterprise-auth"
|
||||||
display_name: "Enterprise Auth-${tox-env}"
|
display_name: "Enterprise Auth-${tox-env}"
|
||||||
matrix_spec: {"tox-env": ["synchro37", "synchro312"], ssl: "ssl"}
|
matrix_spec: {"tox-env": ["synchro-py37", "synchro-py312"], ssl: "ssl"}
|
||||||
run_on:
|
run_on:
|
||||||
- "rhel84-small"
|
- "rhel84-small"
|
||||||
tasks:
|
tasks:
|
||||||
@ -1063,9 +1015,7 @@ buildvariants:
|
|||||||
run_on:
|
run_on:
|
||||||
- "rhel84-small"
|
- "rhel84-small"
|
||||||
expansions:
|
expansions:
|
||||||
TOX_ENV: "py3-sphinx-docs"
|
TOX_ENV: "docs"
|
||||||
INSTALL_TOX: true
|
|
||||||
VIRTUALENV: "/opt/python/3.7/bin/python3 -m virtualenv"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
||||||
tasks:
|
tasks:
|
||||||
- name: "docs"
|
- name: "docs"
|
||||||
@ -1075,9 +1025,7 @@ buildvariants:
|
|||||||
run_on:
|
run_on:
|
||||||
- "rhel84-small"
|
- "rhel84-small"
|
||||||
expansions:
|
expansions:
|
||||||
TOX_ENV: "py3-sphinx-doctest"
|
TOX_ENV: "doctest"
|
||||||
INSTALL_TOX: true
|
|
||||||
VIRTUALENV: "/opt/python/3.7/bin/python3 -m virtualenv"
|
|
||||||
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
PYTHON_BINARY: "/opt/python/3.7/bin/python3"
|
||||||
tasks:
|
tasks:
|
||||||
- name: "doctest"
|
- name: "doctest"
|
||||||
|
|||||||
@ -26,4 +26,4 @@ export GSSAPI_PRINCIPAL=${PRINCIPAL}
|
|||||||
export TOX_TESTENV_PASSENV="*"
|
export TOX_TESTENV_PASSENV="*"
|
||||||
|
|
||||||
# --sitepackages allows use of pykerberos without a test dep.
|
# --sitepackages allows use of pykerberos without a test dep.
|
||||||
/opt/python/3.7/bin/python3 -m tox -e "$TOX_ENV" --sitepackages -- -x test.test_auth
|
/opt/python/3.7/bin/python3 -m tox -m "$TOX_ENV" --sitepackages -- -x test.test_auth
|
||||||
|
|||||||
@ -6,14 +6,16 @@ set -o errexit # Exit the script with error if any of the commands fail
|
|||||||
# AUTH Set to enable authentication. Defaults to "noauth"
|
# AUTH Set to enable authentication. Defaults to "noauth"
|
||||||
# SSL Set to enable SSL. Defaults to "nossl"
|
# SSL Set to enable SSL. Defaults to "nossl"
|
||||||
# TOX_ENV Tox environment name, e.g. "tornado5-py37"
|
# TOX_ENV Tox environment name, e.g. "tornado5-py37"
|
||||||
# TOX_BINARY Path to tox executable
|
|
||||||
# INSTALL_TOX Whether to install tox in a virtualenv
|
|
||||||
# PYTHON_BINARY Path to python
|
# PYTHON_BINARY Path to python
|
||||||
# VIRTUALENV Path to virtualenv script
|
|
||||||
|
|
||||||
AUTH=${AUTH:-noauth}
|
AUTH=${AUTH:-noauth}
|
||||||
SSL=${SSL:-nossl}
|
SSL=${SSL:-nossl}
|
||||||
|
|
||||||
|
if [ -z $PYTHON_BINARY ]; then
|
||||||
|
echo "PYTHON_BINARY is undefined!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$AUTH" != "noauth" ]; then
|
if [ "$AUTH" != "noauth" ]; then
|
||||||
export DB_USER="bob"
|
export DB_USER="bob"
|
||||||
export DB_PASSWORD="pwd123"
|
export DB_PASSWORD="pwd123"
|
||||||
@ -24,24 +26,50 @@ if [ "$SSL" != "nossl" ]; then
|
|||||||
export CA_PEM="$DRIVERS_TOOLS/.evergreen/x509gen/ca.pem"
|
export CA_PEM="$DRIVERS_TOOLS/.evergreen/x509gen/ca.pem"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$TOX_ENV" = "synchro37" ]; then
|
|
||||||
SETUP_ARGS="-- --check-exclude-patterns"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${INSTALL_TOX}" = "true" ]; then
|
# Usage:
|
||||||
$VIRTUALENV motorenv
|
# createvirtualenv /path/to/python /output/path/for/venv
|
||||||
set +o xtrace
|
# * param1: Python binary to use for the virtualenv
|
||||||
if [ -f motorenv/bin/activate ]; then
|
# * param2: Path to the virtualenv to create
|
||||||
source motorenv/bin/activate
|
createvirtualenv () {
|
||||||
|
PYTHON=$1
|
||||||
|
VENVPATH=$2
|
||||||
|
if $PYTHON -m virtualenv --version; then
|
||||||
|
VIRTUALENV="$PYTHON -m virtualenv"
|
||||||
|
elif $PYTHON -m venv -h > /dev/null; then
|
||||||
|
# System virtualenv might not be compatible with the python3 on our path
|
||||||
|
VIRTUALENV="$PYTHON -m venv"
|
||||||
else
|
else
|
||||||
# Windows.
|
echo "Cannot test without virtualenv"
|
||||||
ls -l motorenv
|
exit 1
|
||||||
source motorenv/Scripts/activate
|
|
||||||
fi
|
fi
|
||||||
set -o xtrace
|
# Workaround for bug in older versions of virtualenv.
|
||||||
pip install "tox>=3.18,<4"
|
$VIRTUALENV $VENVPATH || $PYTHON -m venv $VENVPATH
|
||||||
TOX_BINARY=tox
|
if [ "Windows_NT" = "$OS" ]; then
|
||||||
|
# Workaround https://bugs.python.org/issue32451:
|
||||||
|
# mongovenv/Scripts/activate: line 3: $'\r': command not found
|
||||||
|
dos2unix $VENVPATH/Scripts/activate || true
|
||||||
|
. $VENVPATH/Scripts/activate
|
||||||
|
else
|
||||||
|
. $VENVPATH/bin/activate
|
||||||
|
fi
|
||||||
|
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
python -m pip install --upgrade setuptools wheel tox
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if $PYTHON_BINARY -m tox --version; then
|
||||||
|
run_tox() {
|
||||||
|
$PYTHON_BINARY -m tox -m $TOX_ENV "$@"
|
||||||
|
}
|
||||||
|
else # No toolchain present, set up virtualenv before installing tox
|
||||||
|
createvirtualenv "$PYTHON_BINARY" toxenv
|
||||||
|
trap "deactivate; rm -rf toxenv" EXIT HUP
|
||||||
|
python -m pip install tox
|
||||||
|
run_tox() {
|
||||||
|
python -m tox -m $TOX_ENV "$@"
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run the tests, and store the results in Evergreen compatible XUnit XML
|
run_tox "${@:1}"
|
||||||
${TOX_BINARY} -e ${TOX_ENV} ${SETUP_ARGS} "$@"
|
|
||||||
|
|||||||
31
.flake8
Normal file
31
.flake8
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[flake8]
|
||||||
|
max-line-length = 100
|
||||||
|
enable-extensions = G
|
||||||
|
extend-ignore =
|
||||||
|
G200, G202, G001
|
||||||
|
# black adds spaces around ':'
|
||||||
|
E203,
|
||||||
|
# E501 line too long (let black handle line length)
|
||||||
|
E501
|
||||||
|
# B305 `.next()` is not a thing on Python 3. Use the `next()` builtin. For Python 2 compatibility, use `six.next()`.
|
||||||
|
B305
|
||||||
|
per-file-ignores =
|
||||||
|
# F841 local variable 'foo' is assigned to but never used
|
||||||
|
# E731 do not assign a lambda expression, use a def
|
||||||
|
# F811 redefinition of unused 'foo' from line XXX
|
||||||
|
test/*/test_examples.py: F841,E731,F811
|
||||||
|
|
||||||
|
# F811 redefinition of unused 'foo' from line XXX
|
||||||
|
# B011 Do not call assert False since python -O removes these calls. Instead callers should raise AssertionError().
|
||||||
|
|
||||||
|
test/*: F811,B011
|
||||||
|
|
||||||
|
# E402 module level import not at top of file
|
||||||
|
doc/examples/monitoring_example.py: E402
|
||||||
|
|
||||||
|
# F403 'from foo import *' used; unable to detect undefined names
|
||||||
|
# F401 'foo' imported but unused
|
||||||
|
synchro/__init__.py: F403,F401
|
||||||
|
|
||||||
|
# F401 'foo' imported but unused
|
||||||
|
motor/__init__.py: F401
|
||||||
118
.github/workflows/test-python.yml
vendored
118
.github/workflows/test-python.yml
vendored
@ -4,55 +4,34 @@ on:
|
|||||||
push:
|
push:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: tests-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash -eux {0}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
pre-commit:
|
|
||||||
name: pre-commit
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-python@v2
|
|
||||||
- uses: pre-commit/action@v2.0.0
|
|
||||||
with:
|
|
||||||
extra_args: --all-files --hook-stage=manual
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 10
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-20.04]
|
os: [ubuntu-20.04]
|
||||||
python-version: ["3.7", "3.11"]
|
python-version: ["3.7", "3.12"]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
name: CPython ${{ matrix.python-version }}-${{ matrix.os }}
|
name: CPython ${{ matrix.python-version }}-${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
cache-dependency-path: 'setup.py'
|
cache-dependency-path: 'pyproject.toml'
|
||||||
- name: Start MongoDB with Custom Options
|
allow-prereleases: true
|
||||||
run: |
|
|
||||||
mkdir data
|
|
||||||
mongod --fork --dbpath=$(pwd)/data --logpath=$PWD/mongo.log --setParameter enableTestCommands=1
|
|
||||||
- name: Install Python dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install -U pip tox tox-gh-actions setuptools
|
|
||||||
- name: Run tests
|
|
||||||
run: |
|
|
||||||
tox
|
|
||||||
|
|
||||||
docs:
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: 3.7
|
|
||||||
cache: 'pip'
|
|
||||||
cache-dependency-path: 'setup.py'
|
|
||||||
- name: Start MongoDB with Custom Options
|
- name: Start MongoDB with Custom Options
|
||||||
run: |
|
run: |
|
||||||
mkdir data
|
mkdir data
|
||||||
@ -60,30 +39,85 @@ jobs:
|
|||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install -U pip tox
|
python -m pip install -U pip tox
|
||||||
- name: Run docs
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
tox -e py3-sphinx-docs
|
tox -m test
|
||||||
tox -e py3-sphinx-doctest
|
|
||||||
tox -e py3-sphinx-linkcheck
|
lint:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
cache: 'pip'
|
||||||
|
cache-dependency-path: 'pyproject.toml'
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install -U pip tox
|
||||||
|
- name: Run linters
|
||||||
|
run: |
|
||||||
|
tox -m lint-manual
|
||||||
|
tox -m manifest
|
||||||
|
|
||||||
|
docs:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: 3.7
|
||||||
|
cache: 'pip'
|
||||||
|
cache-dependency-path: 'pyproject.toml'
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install -U pip tox
|
||||||
|
- name: Run docs
|
||||||
|
run: tox -m docs
|
||||||
|
- name: Run linkcheck
|
||||||
|
run: tox -m linkcheck
|
||||||
|
- name: Start MongoDB with Custom Options
|
||||||
|
run: |
|
||||||
|
mkdir data
|
||||||
|
mongod --fork --dbpath=$(pwd)/data --logpath=$PWD/mongo.log --setParameter enableTestCommands=1
|
||||||
|
- name: Run doctest
|
||||||
|
run: tox -m doctest
|
||||||
|
|
||||||
|
release:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: 3.7
|
||||||
|
cache: 'pip'
|
||||||
|
cache-dependency-path: 'pyproject.toml'
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install -U pip
|
||||||
|
- name: Run the release script
|
||||||
|
run: |
|
||||||
|
bash release.sh
|
||||||
|
|
||||||
typing:
|
typing:
|
||||||
name: Typing Tests
|
name: Typing Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.7', '3.11']
|
python-version: ['3.7', '3.12']
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
cache-dependency-path: 'setup.py'
|
cache-dependency-path: 'pyproject.toml'
|
||||||
|
allow-prereleases: true
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install -U pip tox
|
python -m pip install -U pip tox
|
||||||
- name: Run mypy
|
- name: Run mypy
|
||||||
run: |
|
run: |
|
||||||
tox -e typecheck-mypy
|
tox -m typecheck-mypy
|
||||||
|
|||||||
@ -29,14 +29,14 @@ Control how the tests connect to MongoDB with these environment variables:
|
|||||||
|
|
||||||
Install `tox`_ and run it from the command line in the repository directory.
|
Install `tox`_ and run it from the command line in the repository directory.
|
||||||
You will need a variety of Python interpreters installed. For a minimal test,
|
You will need a variety of Python interpreters installed. For a minimal test,
|
||||||
ensure you have Python 3.9, and run::
|
ensure you have your desired Python version on your path, and run::
|
||||||
|
|
||||||
> tox -e asyncio-py39
|
> tox -m test
|
||||||
|
|
||||||
The doctests pass with Python 3.7 and a MongoDB 5.0 instance running on
|
The doctests pass with Python 3.7+ and a MongoDB 5.0 instance running on
|
||||||
port 27017:
|
port 27017:
|
||||||
|
|
||||||
> tox -e py3-sphinx-doctest
|
> tox -m doctest
|
||||||
|
|
||||||
.. _tox: https://testrun.org/tox/
|
.. _tox: https://testrun.org/tox/
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ To set up ``pre-commit`` locally, run::
|
|||||||
|
|
||||||
To run ``pre-commit`` manually, run::
|
To run ``pre-commit`` manually, run::
|
||||||
|
|
||||||
> tox -e lint
|
> tox -m lint
|
||||||
|
|
||||||
General Guidelines
|
General Guidelines
|
||||||
------------------
|
------------------
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
include README.rst
|
include README.rst
|
||||||
include LICENSE
|
include LICENSE
|
||||||
include tox.ini
|
include tox.ini
|
||||||
|
include pytest.ini
|
||||||
|
include pyproject.toml
|
||||||
include mypy.ini
|
include mypy.ini
|
||||||
include doc/Makefile
|
include doc/Makefile
|
||||||
include doc/examples/tornado_change_stream_templates/index.html
|
include doc/examples/tornado_change_stream_templates/index.html
|
||||||
@ -17,12 +19,13 @@ recursive-include doc *.bat
|
|||||||
recursive-include synchro *.py
|
recursive-include synchro *.py
|
||||||
recursive-include motor *.pyi
|
recursive-include motor *.pyi
|
||||||
recursive-include motor *.typed
|
recursive-include motor *.typed
|
||||||
|
recursive-include motor *.py
|
||||||
|
|
||||||
|
exclude .flake8
|
||||||
exclude .readthedocs.yaml
|
exclude .readthedocs.yaml
|
||||||
exclude .git-blame-ignore-revs
|
exclude .git-blame-ignore-revs
|
||||||
exclude .pre-commit-config.yaml
|
exclude .pre-commit-config.yaml
|
||||||
exclude release.sh
|
exclude release.sh
|
||||||
exclude ez_setup.py
|
|
||||||
exclude RELEASE.rst
|
exclude RELEASE.rst
|
||||||
exclude CONTRIBUTING.rst
|
exclude CONTRIBUTING.rst
|
||||||
exclude .evergreen/*
|
exclude .evergreen/*
|
||||||
|
|||||||
@ -32,9 +32,9 @@ and a `source distribution <https://packaging.python.org/guides/distributing-pac
|
|||||||
#. Add release notes to `doc/changelog.rst`. Generally just summarize/clarify
|
#. Add release notes to `doc/changelog.rst`. Generally just summarize/clarify
|
||||||
the git log, but you might add some more long form notes for big changes.
|
the git log, but you might add some more long form notes for big changes.
|
||||||
|
|
||||||
#. Search and replace the `devN` version number w/ the new version number (see
|
#. Replace the `devN` version number w/ the new version number (see
|
||||||
note above in `Versioning`_). Make sure version number is updated in
|
note above in `Versioning`_). Make sure version number is updated in
|
||||||
`setup.py` and `motor/__init__.py`. Commit the change and tag the release.
|
``motor/_version.py``. Commit the change and tag the release.
|
||||||
Immediately bump the version number to `dev0` in a new commit::
|
Immediately bump the version number to `dev0` in a new commit::
|
||||||
|
|
||||||
$ # Bump to release version number
|
$ # Bump to release version number
|
||||||
@ -67,7 +67,7 @@ and a `source distribution <https://packaging.python.org/guides/distributing-pac
|
|||||||
new version does not show up automatically, trigger a rebuild of "latest":
|
new version does not show up automatically, trigger a rebuild of "latest":
|
||||||
https://readthedocs.org/projects/motor/builds/
|
https://readthedocs.org/projects/motor/builds/
|
||||||
|
|
||||||
#. Bump the version number to <next version>.dev0 in setup.py/__init__.py,
|
#. Bump the version number to <next version>.dev0 in motor/_version.py,
|
||||||
commit, push.
|
commit, push.
|
||||||
|
|
||||||
#. Publish the release version in Jira.
|
#. Publish the release version in Jira.
|
||||||
|
|||||||
447
ez_setup.py
447
ez_setup.py
@ -1,447 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
"""
|
|
||||||
Setuptools bootstrapping installer.
|
|
||||||
|
|
||||||
Maintained at https://github.com/pypa/setuptools/tree/bootstrap.
|
|
||||||
|
|
||||||
Run this script to install or upgrade setuptools.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import codecs
|
|
||||||
import contextlib
|
|
||||||
import json
|
|
||||||
import optparse
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import textwrap
|
|
||||||
import zipfile
|
|
||||||
from distutils import log
|
|
||||||
|
|
||||||
try:
|
|
||||||
from urllib.parse import urljoin
|
|
||||||
from urllib.request import urlopen
|
|
||||||
except ImportError:
|
|
||||||
from urllib2 import urlopen
|
|
||||||
from urlparse import urljoin
|
|
||||||
|
|
||||||
try:
|
|
||||||
from site import USER_SITE
|
|
||||||
except ImportError:
|
|
||||||
USER_SITE = None
|
|
||||||
|
|
||||||
LATEST = object()
|
|
||||||
DEFAULT_VERSION = LATEST
|
|
||||||
DEFAULT_URL = "https://pypi.io/packages/source/s/setuptools/"
|
|
||||||
DEFAULT_SAVE_DIR = os.curdir
|
|
||||||
|
|
||||||
|
|
||||||
def _python_cmd(*args):
|
|
||||||
"""
|
|
||||||
Execute a command.
|
|
||||||
|
|
||||||
Return True if the command succeeded.
|
|
||||||
"""
|
|
||||||
args = (sys.executable,) + args
|
|
||||||
return subprocess.call(args) == 0
|
|
||||||
|
|
||||||
|
|
||||||
def _install(archive_filename, install_args=()):
|
|
||||||
"""Install Setuptools."""
|
|
||||||
with archive_context(archive_filename):
|
|
||||||
# installing
|
|
||||||
log.warning("Installing Setuptools")
|
|
||||||
if not _python_cmd("setup.py", "install", *install_args):
|
|
||||||
log.warning("Something went wrong during the installation.")
|
|
||||||
log.warning("See the error message above.")
|
|
||||||
# exitcode will be 2
|
|
||||||
return 2
|
|
||||||
|
|
||||||
|
|
||||||
def _build_egg(egg, archive_filename, to_dir):
|
|
||||||
"""Build Setuptools egg."""
|
|
||||||
with archive_context(archive_filename):
|
|
||||||
# building an egg
|
|
||||||
log.warning("Building a Setuptools egg in %s", to_dir)
|
|
||||||
_python_cmd("setup.py", "-q", "bdist_egg", "--dist-dir", to_dir)
|
|
||||||
# returning the result
|
|
||||||
log.warning(egg)
|
|
||||||
if not os.path.exists(egg):
|
|
||||||
raise IOError("Could not build the egg.")
|
|
||||||
|
|
||||||
|
|
||||||
class ContextualZipFile(zipfile.ZipFile):
|
|
||||||
|
|
||||||
"""Supplement ZipFile class to support context manager for Python 2.6."""
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
"""Construct a ZipFile or ContextualZipFile as appropriate."""
|
|
||||||
if hasattr(zipfile.ZipFile, "__exit__"):
|
|
||||||
return zipfile.ZipFile(*args, **kwargs)
|
|
||||||
return super().__new__(cls)
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def archive_context(filename):
|
|
||||||
"""
|
|
||||||
Unzip filename to a temporary directory, set to the cwd.
|
|
||||||
|
|
||||||
The unzipped target is cleaned up after.
|
|
||||||
"""
|
|
||||||
tmpdir = tempfile.mkdtemp()
|
|
||||||
log.warning("Extracting in %s", tmpdir)
|
|
||||||
old_wd = os.getcwd()
|
|
||||||
try:
|
|
||||||
os.chdir(tmpdir)
|
|
||||||
with ContextualZipFile(filename) as archive:
|
|
||||||
archive.extractall()
|
|
||||||
|
|
||||||
# going in the directory
|
|
||||||
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
|
||||||
os.chdir(subdir)
|
|
||||||
log.warning("Now working in %s", subdir)
|
|
||||||
yield
|
|
||||||
|
|
||||||
finally:
|
|
||||||
os.chdir(old_wd)
|
|
||||||
shutil.rmtree(tmpdir)
|
|
||||||
|
|
||||||
|
|
||||||
def _do_download(version, download_base, to_dir, download_delay):
|
|
||||||
"""Download Setuptools."""
|
|
||||||
py_desig = "py{sys.version_info[0]}.{sys.version_info[1]}".format(sys=sys)
|
|
||||||
tp = "setuptools-{version}-{py_desig}.egg"
|
|
||||||
egg = os.path.join(to_dir, tp.format(**locals()))
|
|
||||||
if not os.path.exists(egg):
|
|
||||||
archive = download_setuptools(version, download_base, to_dir, download_delay)
|
|
||||||
_build_egg(egg, archive, to_dir)
|
|
||||||
sys.path.insert(0, egg)
|
|
||||||
|
|
||||||
# Remove previously-imported pkg_resources if present (see
|
|
||||||
# https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
|
|
||||||
if "pkg_resources" in sys.modules:
|
|
||||||
_unload_pkg_resources()
|
|
||||||
|
|
||||||
import setuptools
|
|
||||||
|
|
||||||
setuptools.bootstrap_install_from = egg
|
|
||||||
|
|
||||||
|
|
||||||
def use_setuptools(
|
|
||||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=DEFAULT_SAVE_DIR, download_delay=15
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Ensure that a setuptools version is installed.
|
|
||||||
|
|
||||||
Return None. Raise SystemExit if the requested version
|
|
||||||
or later cannot be installed.
|
|
||||||
"""
|
|
||||||
version = _resolve_version(version)
|
|
||||||
to_dir = os.path.abspath(to_dir)
|
|
||||||
|
|
||||||
# prior to importing, capture the module state for
|
|
||||||
# representative modules.
|
|
||||||
rep_modules = "pkg_resources", "setuptools"
|
|
||||||
imported = set(sys.modules).intersection(rep_modules)
|
|
||||||
|
|
||||||
try:
|
|
||||||
import pkg_resources
|
|
||||||
|
|
||||||
pkg_resources.require("setuptools>=" + version)
|
|
||||||
# a suitable version is already installed
|
|
||||||
return
|
|
||||||
except ImportError:
|
|
||||||
# pkg_resources not available; setuptools is not installed; download
|
|
||||||
pass
|
|
||||||
except pkg_resources.DistributionNotFound:
|
|
||||||
# no version of setuptools was found; allow download
|
|
||||||
pass
|
|
||||||
except pkg_resources.VersionConflict as VC_err:
|
|
||||||
if imported:
|
|
||||||
_conflict_bail(VC_err, version)
|
|
||||||
|
|
||||||
# otherwise, unload pkg_resources to allow the downloaded version to
|
|
||||||
# take precedence.
|
|
||||||
del pkg_resources
|
|
||||||
_unload_pkg_resources()
|
|
||||||
|
|
||||||
return _do_download(version, download_base, to_dir, download_delay)
|
|
||||||
|
|
||||||
|
|
||||||
def _conflict_bail(VC_err, version):
|
|
||||||
"""
|
|
||||||
Setuptools was imported prior to invocation, so it is
|
|
||||||
unsafe to unload it. Bail out.
|
|
||||||
"""
|
|
||||||
conflict_tmpl = textwrap.dedent(
|
|
||||||
"""
|
|
||||||
The required version of setuptools (>={version}) is not available,
|
|
||||||
and can't be installed while this script is running. Please
|
|
||||||
install a more recent version first, using
|
|
||||||
'easy_install -U setuptools'.
|
|
||||||
|
|
||||||
(Currently using {VC_err.args[0]!r})
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
msg = conflict_tmpl.format(**locals())
|
|
||||||
sys.stderr.write(msg)
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
|
|
||||||
def _unload_pkg_resources():
|
|
||||||
sys.meta_path = [
|
|
||||||
importer
|
|
||||||
for importer in sys.meta_path
|
|
||||||
if importer.__class__.__module__ != "pkg_resources.extern"
|
|
||||||
]
|
|
||||||
del_modules = [name for name in sys.modules if name.startswith("pkg_resources")]
|
|
||||||
for mod_name in del_modules:
|
|
||||||
del sys.modules[mod_name]
|
|
||||||
|
|
||||||
|
|
||||||
def _clean_check(cmd, target):
|
|
||||||
"""
|
|
||||||
Run the command to download target.
|
|
||||||
|
|
||||||
If the command fails, clean up before re-raising the error.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
if os.access(target, os.F_OK):
|
|
||||||
os.unlink(target)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def download_file_powershell(url, target):
|
|
||||||
"""
|
|
||||||
Download the file at url to target using Powershell.
|
|
||||||
|
|
||||||
Powershell will validate trust.
|
|
||||||
Raise an exception if the command cannot complete.
|
|
||||||
"""
|
|
||||||
target = os.path.abspath(target)
|
|
||||||
ps_cmd = (
|
|
||||||
"[System.Net.WebRequest]::DefaultWebProxy.Credentials = "
|
|
||||||
"[System.Net.CredentialCache]::DefaultCredentials; "
|
|
||||||
'(new-object System.Net.WebClient).DownloadFile("%(url)s", "%(target)s")' % locals()
|
|
||||||
)
|
|
||||||
cmd = [
|
|
||||||
"powershell",
|
|
||||||
"-Command",
|
|
||||||
ps_cmd,
|
|
||||||
]
|
|
||||||
_clean_check(cmd, target)
|
|
||||||
|
|
||||||
|
|
||||||
def has_powershell():
|
|
||||||
"""Determine if Powershell is available."""
|
|
||||||
if platform.system() != "Windows":
|
|
||||||
return False
|
|
||||||
cmd = ["powershell", "-Command", "echo test"]
|
|
||||||
with open(os.path.devnull, "wb") as devnull:
|
|
||||||
try:
|
|
||||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
download_file_powershell.viable = has_powershell
|
|
||||||
|
|
||||||
|
|
||||||
def download_file_curl(url, target):
|
|
||||||
cmd = ["curl", url, "--location", "--silent", "--output", target]
|
|
||||||
_clean_check(cmd, target)
|
|
||||||
|
|
||||||
|
|
||||||
def has_curl():
|
|
||||||
cmd = ["curl", "--version"]
|
|
||||||
with open(os.path.devnull, "wb") as devnull:
|
|
||||||
try:
|
|
||||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
download_file_curl.viable = has_curl
|
|
||||||
|
|
||||||
|
|
||||||
def download_file_wget(url, target):
|
|
||||||
cmd = ["wget", url, "--quiet", "--output-document", target]
|
|
||||||
_clean_check(cmd, target)
|
|
||||||
|
|
||||||
|
|
||||||
def has_wget():
|
|
||||||
cmd = ["wget", "--version"]
|
|
||||||
with open(os.path.devnull, "wb") as devnull:
|
|
||||||
try:
|
|
||||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
download_file_wget.viable = has_wget
|
|
||||||
|
|
||||||
|
|
||||||
def download_file_insecure(url, target):
|
|
||||||
"""Use Python to download the file, without connection authentication."""
|
|
||||||
src = urlopen(url)
|
|
||||||
try:
|
|
||||||
# Read all the data in one block.
|
|
||||||
data = src.read()
|
|
||||||
finally:
|
|
||||||
src.close()
|
|
||||||
|
|
||||||
# Write all the data in one block to avoid creating a partial file.
|
|
||||||
with open(target, "wb") as dst:
|
|
||||||
dst.write(data)
|
|
||||||
|
|
||||||
|
|
||||||
download_file_insecure.viable = lambda: True
|
|
||||||
|
|
||||||
|
|
||||||
def get_best_downloader():
|
|
||||||
downloaders = (
|
|
||||||
download_file_powershell,
|
|
||||||
download_file_curl,
|
|
||||||
download_file_wget,
|
|
||||||
download_file_insecure,
|
|
||||||
)
|
|
||||||
viable_downloaders = (dl for dl in downloaders if dl.viable())
|
|
||||||
return next(viable_downloaders, None)
|
|
||||||
|
|
||||||
|
|
||||||
def download_setuptools(
|
|
||||||
version=DEFAULT_VERSION,
|
|
||||||
download_base=DEFAULT_URL,
|
|
||||||
to_dir=DEFAULT_SAVE_DIR,
|
|
||||||
delay=15,
|
|
||||||
downloader_factory=get_best_downloader,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Download setuptools from a specified location and return its filename.
|
|
||||||
|
|
||||||
`version` should be a valid setuptools version number that is available
|
|
||||||
as an sdist for download under the `download_base` URL (which should end
|
|
||||||
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
|
||||||
`delay` is the number of seconds to pause before an actual download
|
|
||||||
attempt.
|
|
||||||
|
|
||||||
``downloader_factory`` should be a function taking no arguments and
|
|
||||||
returning a function for downloading a URL to a target.
|
|
||||||
"""
|
|
||||||
version = _resolve_version(version)
|
|
||||||
# making sure we use the absolute path
|
|
||||||
to_dir = os.path.abspath(to_dir)
|
|
||||||
zip_name = "setuptools-%s.zip" % version
|
|
||||||
url = download_base + zip_name
|
|
||||||
saveto = os.path.join(to_dir, zip_name)
|
|
||||||
if not os.path.exists(saveto): # Avoid repeated downloads
|
|
||||||
log.warning("Downloading %s", url)
|
|
||||||
downloader = downloader_factory()
|
|
||||||
downloader(url, saveto)
|
|
||||||
return os.path.realpath(saveto)
|
|
||||||
|
|
||||||
|
|
||||||
def _resolve_version(version):
|
|
||||||
"""
|
|
||||||
Resolve LATEST version
|
|
||||||
"""
|
|
||||||
if version is not LATEST:
|
|
||||||
return version
|
|
||||||
|
|
||||||
meta_url = urljoin(DEFAULT_URL, "/pypi/setuptools/json")
|
|
||||||
resp = urlopen(meta_url)
|
|
||||||
with contextlib.closing(resp):
|
|
||||||
try:
|
|
||||||
charset = resp.info().get_content_charset()
|
|
||||||
except Exception:
|
|
||||||
# Python 2 compat; assume UTF-8
|
|
||||||
charset = "UTF-8"
|
|
||||||
reader = codecs.getreader(charset)
|
|
||||||
doc = json.load(reader(resp))
|
|
||||||
|
|
||||||
return str(doc["info"]["version"])
|
|
||||||
|
|
||||||
|
|
||||||
def _build_install_args(options):
|
|
||||||
"""
|
|
||||||
Build the arguments to 'python setup.py install' on the setuptools package.
|
|
||||||
|
|
||||||
Returns list of command line arguments.
|
|
||||||
"""
|
|
||||||
return ["--user"] if options.user_install else []
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_args():
|
|
||||||
"""Parse the command line for options."""
|
|
||||||
parser = optparse.OptionParser()
|
|
||||||
parser.add_option(
|
|
||||||
"--user",
|
|
||||||
dest="user_install",
|
|
||||||
action="store_true",
|
|
||||||
default=False,
|
|
||||||
help="install in user site package",
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"--download-base",
|
|
||||||
dest="download_base",
|
|
||||||
metavar="URL",
|
|
||||||
default=DEFAULT_URL,
|
|
||||||
help="alternative URL from where to download the setuptools package",
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"--insecure",
|
|
||||||
dest="downloader_factory",
|
|
||||||
action="store_const",
|
|
||||||
const=lambda: download_file_insecure,
|
|
||||||
default=get_best_downloader,
|
|
||||||
help="Use internal, non-validating downloader",
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"--version",
|
|
||||||
help="Specify which version to download",
|
|
||||||
default=DEFAULT_VERSION,
|
|
||||||
)
|
|
||||||
parser.add_option(
|
|
||||||
"--to-dir",
|
|
||||||
help="Directory to save (and re-use) package",
|
|
||||||
default=DEFAULT_SAVE_DIR,
|
|
||||||
)
|
|
||||||
options, args = parser.parse_args()
|
|
||||||
# positional arguments are ignored
|
|
||||||
return options
|
|
||||||
|
|
||||||
|
|
||||||
def _download_args(options):
|
|
||||||
"""Return args for download_setuptools function from cmdline args."""
|
|
||||||
return dict(
|
|
||||||
version=options.version,
|
|
||||||
download_base=options.download_base,
|
|
||||||
downloader_factory=options.downloader_factory,
|
|
||||||
to_dir=options.to_dir,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Install or upgrade setuptools and EasyInstall."""
|
|
||||||
options = _parse_args()
|
|
||||||
archive = download_setuptools(**_download_args(options))
|
|
||||||
return _install(archive, _build_install_args(options))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
@ -1325,14 +1325,14 @@ class AgnosticCollection(AgnosticBaseProperties):
|
|||||||
# Latent cursor that will send initial command on first "async for".
|
# Latent cursor that will send initial command on first "async for".
|
||||||
return cursor_class(self, self._async_list_indexes, session=session, **kwargs)
|
return cursor_class(self, self._async_list_indexes, session=session, **kwargs)
|
||||||
|
|
||||||
def _list_search_indexes(self, session=None, **kwargs):
|
def _list_search_indexes(self, *args, **kwargs):
|
||||||
"""Return a cursor over search indexes for the current collection."""
|
"""Return a cursor over search indexes for the current collection."""
|
||||||
cursor_class = create_class_with_framework(
|
cursor_class = create_class_with_framework(
|
||||||
AgnosticLatentCommandCursor, self._framework, self.__module__
|
AgnosticLatentCommandCursor, self._framework, self.__module__
|
||||||
)
|
)
|
||||||
|
|
||||||
# Latent cursor that will send initial command on first "async for".
|
# Latent cursor that will send initial command on first "async for".
|
||||||
return cursor_class(self, self._async_list_search_indexes, session=session, **kwargs)
|
return cursor_class(self, self._async_list_search_indexes, *args, **kwargs)
|
||||||
|
|
||||||
# TODO: MOTOR-1169
|
# TODO: MOTOR-1169
|
||||||
if hasattr(Collection, "list_search_indexes"):
|
if hasattr(Collection, "list_search_indexes"):
|
||||||
|
|||||||
82
pyproject.toml
Normal file
82
pyproject.toml
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>61.0"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "motor"
|
||||||
|
dynamic = ["version"]
|
||||||
|
description = "Non-blocking MongoDB driver for Tornado or asyncio"
|
||||||
|
readme = "README.rst"
|
||||||
|
license = { file = "LICENSE" }
|
||||||
|
requires-python = ">=3.7"
|
||||||
|
authors = [
|
||||||
|
{ name = "A. Jesse Jiryu Davis", email = "jesse@mongodb.com" },
|
||||||
|
]
|
||||||
|
keywords = [
|
||||||
|
"asyncio",
|
||||||
|
"bson",
|
||||||
|
"gridfs",
|
||||||
|
"mongo",
|
||||||
|
"mongodb",
|
||||||
|
"motor",
|
||||||
|
"pymongo",
|
||||||
|
"tornado",
|
||||||
|
]
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 5 - Production/Stable",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"License :: OSI Approved :: Apache Software License",
|
||||||
|
"Natural Language :: English",
|
||||||
|
"Operating System :: MacOS :: MacOS X",
|
||||||
|
"Operating System :: Microsoft :: Windows",
|
||||||
|
"Operating System :: Unix",
|
||||||
|
"Typing :: Typed",
|
||||||
|
"Programming Language :: Python",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"pymongo>=4.4,<5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
aws = [
|
||||||
|
"pymongo[aws]>=4.4,<5",
|
||||||
|
]
|
||||||
|
encryption = [
|
||||||
|
"pymongo[encryption]>=4.4,<5",
|
||||||
|
]
|
||||||
|
gssapi = [
|
||||||
|
"pymongo[gssapi]>=4.4,<5",
|
||||||
|
]
|
||||||
|
ocsp = [
|
||||||
|
"pymongo[ocsp]>=4.4,<5",
|
||||||
|
]
|
||||||
|
snappy = [
|
||||||
|
"pymongo[snappy]>=4.4,<5",
|
||||||
|
]
|
||||||
|
srv = [
|
||||||
|
"pymongo[srv]>=4.4,<5",
|
||||||
|
]
|
||||||
|
test = [
|
||||||
|
"pytest>=7", "mockupdb", "tornado>=5", "aiohttp", "motor[encryption]"
|
||||||
|
]
|
||||||
|
zstd = [
|
||||||
|
"pymongo[zstd]>=4.4,<5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://github.com/mongodb/motor/"
|
||||||
|
|
||||||
|
[tool.setuptools.dynamic]
|
||||||
|
version = {attr = "motor._version.version"}
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
include = ["motor"]
|
||||||
15
pytest.ini
Normal file
15
pytest.ini
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[pytest]
|
||||||
|
testpaths =
|
||||||
|
test
|
||||||
|
addopts = -ra --junitxml=xunit-results/TEST-results.xml
|
||||||
|
filterwarnings =
|
||||||
|
error
|
||||||
|
ignore:Bare functions are deprecated, use async ones:DeprecationWarning
|
||||||
|
ignore:Application.make_handler:DeprecationWarning
|
||||||
|
ignore:unclosed <socket.socket:ResourceWarning
|
||||||
|
ignore:unclosed event loop:ResourceWarning
|
||||||
|
ignore: The fetch_next property is deprecated:DeprecationWarning
|
||||||
|
ignore:The next_object method is deprecated:DeprecationWarning
|
||||||
|
ignore:unclosed <ssl.SSLSocket:ResourceWarning
|
||||||
|
ignore:datetime.utcfromtimestamp:DeprecationWarning
|
||||||
|
ignore:datetime.utcnow:DeprecationWarning
|
||||||
15
release.sh
15
release.sh
@ -8,22 +8,15 @@
|
|||||||
set -o xtrace # Write all commands first to stderr
|
set -o xtrace # Write all commands first to stderr
|
||||||
set -o errexit # Exit the script with error if any of the commands fail
|
set -o errexit # Exit the script with error if any of the commands fail
|
||||||
|
|
||||||
# Only build distributions with Python 3.5.2 or later.
|
|
||||||
python3 -c "import sys; exit(sys.version_info < (3, 5, 2))"
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "ERROR: Run this script with Python 3.5.2 or later."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cleanup destinations
|
# Cleanup destinations
|
||||||
rm -rf build
|
rm -rf build
|
||||||
rm -rf dist
|
rm -rf dist
|
||||||
|
|
||||||
# Build the source dist first
|
# Install deps
|
||||||
python3 setup.py sdist
|
python3 -m pip install build
|
||||||
|
|
||||||
# Build the wheel
|
# Build the source dist and wheel
|
||||||
python3 setup.py bdist_wheel
|
python3 -m build .
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
rm -rf build
|
rm -rf build
|
||||||
|
|||||||
192
setup.py
192
setup.py
@ -1,193 +1,3 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if sys.version_info[:2] < (3, 10):
|
|
||||||
from distutils.cmd import Command
|
|
||||||
from distutils.errors import DistutilsOptionError as OptionError
|
|
||||||
else:
|
|
||||||
from setuptools import Command
|
|
||||||
from setuptools.errors import OptionError
|
|
||||||
|
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
if sys.version_info[:2] < (3, 7):
|
setup()
|
||||||
raise Exception("This version of Motor requires Python>=3.7")
|
|
||||||
|
|
||||||
classifiers = """\
|
|
||||||
Intended Audience :: Developers
|
|
||||||
License :: OSI Approved :: Apache Software License
|
|
||||||
Development Status :: 5 - Production/Stable
|
|
||||||
Natural Language :: English
|
|
||||||
Programming Language :: Python :: 3
|
|
||||||
Programming Language :: Python :: 3.7
|
|
||||||
Programming Language :: Python :: 3.8
|
|
||||||
Programming Language :: Python :: 3.9
|
|
||||||
Programming Language :: Python :: 3.10
|
|
||||||
Programming Language :: Python :: 3.11
|
|
||||||
Operating System :: MacOS :: MacOS X
|
|
||||||
Operating System :: Unix
|
|
||||||
Operating System :: Microsoft :: Windows
|
|
||||||
Programming Language :: Python
|
|
||||||
Programming Language :: Python :: Implementation :: CPython
|
|
||||||
Programming Language :: Python :: Implementation :: PyPy
|
|
||||||
Typing :: Typed
|
|
||||||
"""
|
|
||||||
|
|
||||||
description = "Non-blocking MongoDB driver for Tornado or asyncio"
|
|
||||||
|
|
||||||
with open("README.rst") as readme:
|
|
||||||
long_description = readme.read()
|
|
||||||
|
|
||||||
pymongo_ver = ">=4.4,<5"
|
|
||||||
|
|
||||||
install_requires = ["pymongo" + pymongo_ver]
|
|
||||||
|
|
||||||
extras_require = {
|
|
||||||
"encryption": ["pymongo[encryption]" + pymongo_ver],
|
|
||||||
"ocsp": ["pymongo[ocsp]" + pymongo_ver],
|
|
||||||
"snappy": ["pymongo[snappy]" + pymongo_ver],
|
|
||||||
"zstd": ["pymongo[zstd]" + pymongo_ver],
|
|
||||||
"aws": ["pymongo[aws]" + pymongo_ver],
|
|
||||||
"srv": ["pymongo[srv]" + pymongo_ver],
|
|
||||||
"gssapi": ["pymongo[gssapi]" + pymongo_ver],
|
|
||||||
}
|
|
||||||
|
|
||||||
tests_require = ["mockupdb>=1.4.0"]
|
|
||||||
|
|
||||||
|
|
||||||
class test(Command):
|
|
||||||
description = "run the tests"
|
|
||||||
|
|
||||||
user_options = [
|
|
||||||
("test-module=", "m", "Discover tests in specified module"),
|
|
||||||
("test-suite=", "s", "Test suite to run (e.g. 'some_module.test_suite')"),
|
|
||||||
("failfast", "f", "Stop running tests on first failure or error"),
|
|
||||||
("tornado-warnings", "w", "Let Tornado log warnings"),
|
|
||||||
("xunit-output=", "x", "Generate a results directory with XUnit XML format"),
|
|
||||||
]
|
|
||||||
|
|
||||||
def initialize_options(self):
|
|
||||||
self.test_module = None
|
|
||||||
self.test_suite = None
|
|
||||||
self.failfast = False
|
|
||||||
self.tornado_warnings = False
|
|
||||||
self.xunit_output = None
|
|
||||||
|
|
||||||
def finalize_options(self):
|
|
||||||
if self.test_suite is None and self.test_module is None:
|
|
||||||
self.test_module = "test"
|
|
||||||
elif self.test_module is not None and self.test_suite is not None:
|
|
||||||
raise OptionError("You may specify a module or suite, but not both")
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
# Installing required packages, running egg_info and build_ext are
|
|
||||||
# part of normal operation for setuptools.command.test.test. Motor
|
|
||||||
# has no extensions so build_ext is a no-op.
|
|
||||||
if self.distribution.install_requires:
|
|
||||||
self.distribution.fetch_build_eggs(self.distribution.install_requires)
|
|
||||||
if self.distribution.tests_require:
|
|
||||||
self.distribution.fetch_build_eggs(self.distribution.tests_require)
|
|
||||||
if self.xunit_output:
|
|
||||||
self.distribution.fetch_build_eggs(["unittest-xml-reporting>=1.14.0,<2.0.0a0"])
|
|
||||||
self.run_command("egg_info")
|
|
||||||
build_ext_cmd = self.reinitialize_command("build_ext")
|
|
||||||
build_ext_cmd.inplace = 1
|
|
||||||
self.run_command("build_ext")
|
|
||||||
|
|
||||||
from test import MotorTestLoader, env, suppress_tornado_warnings
|
|
||||||
from test import test_environment as testenv
|
|
||||||
|
|
||||||
loader = MotorTestLoader()
|
|
||||||
loader.avoid("high_availability", reason="Runs separately")
|
|
||||||
|
|
||||||
if not (testenv.HAVE_ASYNCIO or testenv.HAVE_TORNADO):
|
|
||||||
raise ImportError("No tornado nor asyncio")
|
|
||||||
elif not testenv.HAVE_TORNADO:
|
|
||||||
loader.avoid("tornado_tests", reason="no tornado")
|
|
||||||
elif not testenv.HAVE_ASYNCIO:
|
|
||||||
loader.avoid("asyncio_tests", reason="no asyncio")
|
|
||||||
|
|
||||||
if not testenv.HAVE_AIOHTTP:
|
|
||||||
loader.avoid("asyncio_tests.test_aiohttp_gridfs", reason="no aiohttp")
|
|
||||||
|
|
||||||
# Decide if we can run async / await tests with Tornado.
|
|
||||||
if not testenv.HAVE_TORNADO:
|
|
||||||
test_motor_await = "tornado_tests.test_motor_await"
|
|
||||||
loader.avoid(test_motor_await, reason="no tornado")
|
|
||||||
|
|
||||||
if self.test_suite is None:
|
|
||||||
suite = loader.discover(self.test_module)
|
|
||||||
else:
|
|
||||||
suite = loader.loadTestsFromName(self.test_suite)
|
|
||||||
|
|
||||||
runner_kwargs = dict(verbosity=2, failfast=self.failfast)
|
|
||||||
|
|
||||||
if self.xunit_output:
|
|
||||||
try:
|
|
||||||
from xmlrunner import XMLTestRunner
|
|
||||||
except ImportError:
|
|
||||||
self.xunit_output = False
|
|
||||||
else:
|
|
||||||
runner_kwargs["output"] = self.xunit_output
|
|
||||||
runner_class = XMLTestRunner
|
|
||||||
|
|
||||||
if not self.xunit_output:
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
runner_class = unittest.TextTestRunner
|
|
||||||
|
|
||||||
runner = runner_class(**runner_kwargs)
|
|
||||||
if "SKIP_ENV_SETUP" not in os.environ:
|
|
||||||
env.setup()
|
|
||||||
if not self.tornado_warnings:
|
|
||||||
suppress_tornado_warnings()
|
|
||||||
|
|
||||||
result = runner.run(suite)
|
|
||||||
sys.exit(not result.wasSuccessful())
|
|
||||||
|
|
||||||
|
|
||||||
packages = [
|
|
||||||
"motor",
|
|
||||||
"motor.frameworks",
|
|
||||||
"motor.frameworks.tornado",
|
|
||||||
"motor.frameworks.asyncio",
|
|
||||||
"motor.aiohttp",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
version_ns = {}
|
|
||||||
with open("motor/_version.py") as fp:
|
|
||||||
exec(fp.read(), version_ns)
|
|
||||||
version = version_ns["version"]
|
|
||||||
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="motor",
|
|
||||||
version=version,
|
|
||||||
packages=packages,
|
|
||||||
description=description,
|
|
||||||
long_description=long_description,
|
|
||||||
author="A. Jesse Jiryu Davis",
|
|
||||||
author_email="jesse@mongodb.com",
|
|
||||||
url="https://github.com/mongodb/motor/",
|
|
||||||
python_requires=">=3.7",
|
|
||||||
install_requires=install_requires,
|
|
||||||
extras_require=extras_require,
|
|
||||||
license="http://www.apache.org/licenses/LICENSE-2.0",
|
|
||||||
classifiers=[c for c in classifiers.split("\n") if c],
|
|
||||||
keywords=[
|
|
||||||
"mongo",
|
|
||||||
"mongodb",
|
|
||||||
"pymongo",
|
|
||||||
"gridfs",
|
|
||||||
"bson",
|
|
||||||
"motor",
|
|
||||||
"tornado",
|
|
||||||
"asyncio",
|
|
||||||
],
|
|
||||||
tests_require=tests_require,
|
|
||||||
test_suite="test",
|
|
||||||
zip_safe=False,
|
|
||||||
cmdclass={"test": test},
|
|
||||||
)
|
|
||||||
|
|||||||
@ -490,11 +490,7 @@ class Collection(Synchro):
|
|||||||
aggregate = WrapOutgoing()
|
aggregate = WrapOutgoing()
|
||||||
aggregate_raw_batches = WrapOutgoing()
|
aggregate_raw_batches = WrapOutgoing()
|
||||||
list_indexes = WrapOutgoing()
|
list_indexes = WrapOutgoing()
|
||||||
create_search_index = WrapOutgoing()
|
|
||||||
create_search_indexes = WrapOutgoing()
|
|
||||||
drop_search_index = WrapOutgoing()
|
|
||||||
list_search_indexes = WrapOutgoing()
|
list_search_indexes = WrapOutgoing()
|
||||||
update_search_index = WrapOutgoing()
|
|
||||||
watch = WrapOutgoing()
|
watch = WrapOutgoing()
|
||||||
__bool__ = WrapOutgoing()
|
__bool__ = WrapOutgoing()
|
||||||
|
|
||||||
|
|||||||
@ -188,6 +188,8 @@ excluded_tests = [
|
|||||||
"TestUnifiedPoolClearedError.test_PoolClearedError_does_not_mark_server_unknown",
|
"TestUnifiedPoolClearedError.test_PoolClearedError_does_not_mark_server_unknown",
|
||||||
# These tests have hard-coded values that differ from motor.
|
# These tests have hard-coded values that differ from motor.
|
||||||
"TestClient.test_handshake.*",
|
"TestClient.test_handshake.*",
|
||||||
|
# This test is not a valid unittest target.
|
||||||
|
"TestRangeQueryProse.run_test_cases",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -14,10 +14,8 @@
|
|||||||
|
|
||||||
"""Test Motor, an asynchronous driver for MongoDB and Tornado."""
|
"""Test Motor, an asynchronous driver for MongoDB and Tornado."""
|
||||||
|
|
||||||
import logging
|
|
||||||
import unittest
|
|
||||||
from test.test_environment import CLIENT_PEM, db_user, env # noqa: F401
|
from test.test_environment import CLIENT_PEM, db_user, env # noqa: F401
|
||||||
from unittest import SkipTest
|
from unittest import SkipTest # noqa: F401
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Enable the fault handler to dump the traceback of each running
|
# Enable the fault handler to dump the traceback of each running
|
||||||
@ -33,45 +31,6 @@ except ImportError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def suppress_tornado_warnings():
|
|
||||||
for name in ["tornado.general", "tornado.access"]:
|
|
||||||
logger = logging.getLogger(name)
|
|
||||||
logger.setLevel(logging.ERROR)
|
|
||||||
|
|
||||||
|
|
||||||
class SkippedModule(object):
|
|
||||||
def __init__(self, name, reason):
|
|
||||||
def runTest(self):
|
|
||||||
raise SkipTest(str(reason))
|
|
||||||
|
|
||||||
self.test_case = type(str(name), (unittest.TestCase,), {"runTest": runTest})
|
|
||||||
|
|
||||||
|
|
||||||
class MotorTestLoader(unittest.TestLoader):
|
|
||||||
def __init__(self, avoid=None, reason=None):
|
|
||||||
super().__init__()
|
|
||||||
self._avoid = []
|
|
||||||
|
|
||||||
def avoid(self, *prefixes, **kwargs):
|
|
||||||
"""Skip a module.
|
|
||||||
|
|
||||||
The usual "raise SkipTest" from a module doesn't work if the module
|
|
||||||
won't even parse in Python 2, so prevent TestLoader from importing
|
|
||||||
modules with the given prefix.
|
|
||||||
|
|
||||||
"prefix" is a path prefix like "asyncio_tests".
|
|
||||||
"""
|
|
||||||
for prefix in prefixes:
|
|
||||||
self._avoid.append((prefix, kwargs["reason"]))
|
|
||||||
|
|
||||||
def _get_module_from_name(self, name):
|
|
||||||
for prefix, reason in self._avoid:
|
|
||||||
if name.startswith(prefix):
|
|
||||||
return SkippedModule(name, reason)
|
|
||||||
|
|
||||||
return super()._get_module_from_name(name)
|
|
||||||
|
|
||||||
|
|
||||||
class MockRequestHandler(object):
|
class MockRequestHandler(object):
|
||||||
"""For testing MotorGridOut.stream_to_handler."""
|
"""For testing MotorGridOut.stream_to_handler."""
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,8 @@ class TestAsyncIOSSL(unittest.TestCase):
|
|||||||
self.loop = asyncio.new_event_loop()
|
self.loop = asyncio.new_event_loop()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
if not hasattr(self, "loop"):
|
||||||
|
return
|
||||||
self.loop.stop()
|
self.loop.stop()
|
||||||
self.loop.run_forever()
|
self.loop.run_forever()
|
||||||
self.loop.close()
|
self.loop.close()
|
||||||
|
|||||||
@ -104,6 +104,8 @@ def is_server_resolvable():
|
|||||||
|
|
||||||
|
|
||||||
class TestEnvironment(object):
|
class TestEnvironment(object):
|
||||||
|
__test__ = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.initialized = False
|
self.initialized = False
|
||||||
self.host = None
|
self.host = None
|
||||||
@ -369,3 +371,5 @@ class TestEnvironment(object):
|
|||||||
|
|
||||||
|
|
||||||
env = TestEnvironment()
|
env = TestEnvironment()
|
||||||
|
if "SKIP_ENV_SETUP" not in os.environ:
|
||||||
|
env.setup()
|
||||||
|
|||||||
@ -101,7 +101,8 @@ class MotorTest(testing.AsyncTestCase):
|
|||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
env.sync_cx.motor_test.test_collection.delete_many({})
|
env.sync_cx.motor_test.test_collection.delete_many({})
|
||||||
self.cx.close()
|
if hasattr(self, "cx"):
|
||||||
|
self.cx.close()
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
"""Test Motor, an asynchronous driver for MongoDB and Tornado."""
|
"""Test Motor, an asynchronous driver for MongoDB and Tornado."""
|
||||||
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import test
|
import test
|
||||||
import unittest
|
import unittest
|
||||||
@ -158,6 +159,7 @@ class ExecutorForkTest(MotorTest):
|
|||||||
parent_conn, child_conn = Pipe()
|
parent_conn, child_conn = Pipe()
|
||||||
lock_pid = os.fork()
|
lock_pid = os.fork()
|
||||||
if lock_pid == 0: # Child
|
if lock_pid == 0: # Child
|
||||||
|
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||||
self.loop = IOLoop.current()
|
self.loop = IOLoop.current()
|
||||||
client = self.motor_client()
|
client = self.motor_client()
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -191,7 +191,7 @@ class TestTransactionsConvenientAPI(MotorTest):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
listener.started_command_names(), ["insert", "commitTransaction", "commitTransaction"]
|
listener.started_command_names(), ["insert", "commitTransaction", "commitTransaction"]
|
||||||
)
|
)
|
||||||
self.set_fail_point(client, {"configureFailPoint": "failCommand", "mode": "off"})
|
await self.set_fail_point(client, {"configureFailPoint": "failCommand", "mode": "off"})
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@ -72,6 +72,8 @@ def get_primary_pool(client):
|
|||||||
|
|
||||||
# Ignore auth commands like saslStart, so we can assert lsid is in all commands.
|
# Ignore auth commands like saslStart, so we can assert lsid is in all commands.
|
||||||
class TestListener(monitoring.CommandListener):
|
class TestListener(monitoring.CommandListener):
|
||||||
|
__test__ = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.results = defaultdict(list)
|
self.results = defaultdict(list)
|
||||||
|
|
||||||
|
|||||||
215
tox.ini
215
tox.ini
@ -4,41 +4,45 @@
|
|||||||
# Adapted from Tornado's tox.ini.
|
# Adapted from Tornado's tox.ini.
|
||||||
|
|
||||||
[tox]
|
[tox]
|
||||||
|
requires =
|
||||||
|
tox>=4
|
||||||
|
|
||||||
envlist =
|
envlist =
|
||||||
# Tornado 5 supports Python 3.4+.
|
# Run the unit test suite
|
||||||
tornado5-{py37},
|
test
|
||||||
|
|
||||||
# Tornado 6 supports Python 3.5+.
|
|
||||||
tornado6-{pypy37,py37,py38,py39,py310,py311,py312},
|
|
||||||
|
|
||||||
# Test Tornado's dev version in a few configurations.
|
|
||||||
tornado_git-{py38},
|
|
||||||
|
|
||||||
# Ensure the sphinx build has no errors or warnings.
|
# Ensure the sphinx build has no errors or warnings.
|
||||||
py3-sphinx-docs,
|
docs,
|
||||||
|
|
||||||
# Run the doctests, include examples and tutorial, via Sphinx.
|
# Run the doctests, include examples and tutorial, via Sphinx.
|
||||||
py3-sphinx-doctest,
|
doctest,
|
||||||
|
# Check links of sphinx docs
|
||||||
# asyncio without Tornado.
|
linkcheck,
|
||||||
asyncio-{py37,py38,py39,py310,py311,py312},
|
|
||||||
|
|
||||||
# Test with the latest PyMongo.
|
# Test with the latest PyMongo.
|
||||||
py3-pymongo-latest,
|
test-pymongo-latest,
|
||||||
|
|
||||||
# Apply PyMongo's test suite to Motor via Synchro.
|
# Apply PyMongo's test suite to Motor via Synchro.
|
||||||
synchro37
|
synchro
|
||||||
synchro312
|
|
||||||
|
|
||||||
# Run pre-commit on all files.
|
# Run pre-commit on all files.
|
||||||
lint
|
lint
|
||||||
|
# Run pre-commit on all files with manual checks.
|
||||||
|
lint-manual
|
||||||
# Check the sdist integrity.
|
# Check the sdist integrity.
|
||||||
manifest
|
manifest
|
||||||
|
|
||||||
# Typecheck with mypy
|
# Typecheck with mypy
|
||||||
typecheck-mypy
|
typecheck-mypy
|
||||||
|
|
||||||
|
|
||||||
|
labels = # Use labels and -m instead of -e so that tox -m <label> fails instantly if the label does not exist
|
||||||
|
test = test
|
||||||
|
docs = docs
|
||||||
|
doctest = doctest
|
||||||
|
checklink = checklink
|
||||||
|
test-pymongo-latest = test-pymongo-latest
|
||||||
|
synchro = synchro
|
||||||
|
lint = lint
|
||||||
|
lint-manual = lint-manual
|
||||||
|
linkcheck = linkcheck
|
||||||
|
manifest = manifest
|
||||||
|
typecheck-mypy = typecheck-mypy
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
passenv =
|
passenv =
|
||||||
DB_IP
|
DB_IP
|
||||||
@ -54,152 +58,85 @@ passenv =
|
|||||||
FLE_AZURE_CLIENTSECRET
|
FLE_AZURE_CLIENTSECRET
|
||||||
FLE_GCP_EMAIL
|
FLE_GCP_EMAIL
|
||||||
FLE_GCP_PRIVATEKEY
|
FLE_GCP_PRIVATEKEY
|
||||||
|
AIOHTTP_NO_EXTENSIONS
|
||||||
|
|
||||||
|
[testenv:test]
|
||||||
basepython =
|
# TODO: Remove as part of MOTOR-1163
|
||||||
py37: {env:PYTHON_BINARY:python3.7}
|
setenv = AIOHTTP_NO_EXTENSIONS=1
|
||||||
py38: {env:PYTHON_BINARY:python3.8}
|
|
||||||
py39: {env:PYTHON_BINARY:python3.9}
|
|
||||||
py310: {env:PYTHON_BINARY:python3.10}
|
|
||||||
py311: {env:PYTHON_BINARY:python3.11}
|
|
||||||
py312: {env:PYTHON_BINARY:python3.12}
|
|
||||||
pypy37: {env:PYTHON_BINARY:pypy3}
|
|
||||||
|
|
||||||
synchro37: {env:PYTHON_BINARY:python3.7}
|
|
||||||
synchro312: {env:PYTHON_BINARY:python3.12}
|
|
||||||
|
|
||||||
# Default Python 3 when we don't care about minor version.
|
|
||||||
py3,lint,manifest: {env:PYTHON_BINARY:python3}
|
|
||||||
|
|
||||||
deps =
|
|
||||||
tornado5: tornado>=5,<6
|
|
||||||
tornado6: tornado>=6,<7
|
|
||||||
tornado_git: git+https://github.com/tornadoweb/tornado.git
|
|
||||||
|
|
||||||
{py37,py38,py39,py310,py311}: aiohttp
|
|
||||||
|
|
||||||
py312: setuptools==68.0.0
|
|
||||||
|
|
||||||
sphinx: sphinx
|
|
||||||
sphinx: aiohttp
|
|
||||||
sphinx: tornado
|
|
||||||
|
|
||||||
py3-pymongo-latest: tornado>=5,<6
|
|
||||||
|
|
||||||
synchro37: tornado>=6,<7
|
|
||||||
synchro37: nose
|
|
||||||
synchro37: pytest
|
|
||||||
|
|
||||||
synchro312: tornado>=6,<7
|
|
||||||
synchro312: pynose
|
|
||||||
synchro312: setuptools==68.0.0
|
|
||||||
synchro312: pytest
|
|
||||||
|
|
||||||
pypy37: cryptography<3
|
|
||||||
setenv =
|
|
||||||
PYTHONWARNINGS="error,ignore:The distutils package is deprecated:DeprecationWarning"
|
|
||||||
commands =
|
commands =
|
||||||
python --version
|
python --version
|
||||||
python setup.py test --xunit-output=xunit-results {posargs}
|
python -m pytest -v {posargs}
|
||||||
|
extras =
|
||||||
|
test
|
||||||
|
|
||||||
|
[testenv:docs]
|
||||||
|
setenv = PYTHONWARNINGS=
|
||||||
|
deps =
|
||||||
|
-rdoc/docs-requirements.txt
|
||||||
|
changedir = doc
|
||||||
|
commands =
|
||||||
|
python -m sphinx -q -E -W -b html . {envtmpdir}/html {posargs}
|
||||||
|
|
||||||
|
[testenv:doctest]
|
||||||
|
setenv = PYTHONHASHSEED=0
|
||||||
|
deps =
|
||||||
|
-rdoc/docs-requirements.txt
|
||||||
|
changedir = doc
|
||||||
|
commands =
|
||||||
|
python -m sphinx -q -E -b doctest . {envtmpdir}/doctest {posargs}
|
||||||
|
|
||||||
|
[testenv:linkcheck]
|
||||||
|
setenv = PYTHONHASHSEED=0
|
||||||
|
deps =
|
||||||
|
-rdoc/docs-requirements.txt
|
||||||
|
changedir = doc
|
||||||
|
commands =
|
||||||
|
python -m sphinx -q -E -b linkcheck . {envtmpdir}/linkcheck {posargs}
|
||||||
|
|
||||||
|
[testenv:test-pymongo-latest]
|
||||||
extras =
|
extras =
|
||||||
encryption
|
encryption
|
||||||
|
test
|
||||||
[testenv:py3-sphinx-docs]
|
|
||||||
setenv = PYTHONWARNINGS=
|
|
||||||
changedir = doc
|
|
||||||
commands =
|
|
||||||
sphinx-build -q -E -W -b html . {envtmpdir}/html {posargs}
|
|
||||||
|
|
||||||
[testenv:py3-sphinx-doctest]
|
|
||||||
setenv = PYTHONHASHSEED=0
|
|
||||||
changedir = doc
|
|
||||||
commands =
|
|
||||||
sphinx-build -q -E -b doctest . {envtmpdir}/doctest {posargs}
|
|
||||||
|
|
||||||
[testenv:py3-sphinx-linkcheck]
|
|
||||||
setenv = PYTHONHASHSEED=0
|
|
||||||
changedir = doc
|
|
||||||
commands =
|
|
||||||
sphinx-build -q -E -b linkcheck . {envtmpdir}/linkcheck {posargs}
|
|
||||||
|
|
||||||
[testenv:py3-pymongo-latest]
|
|
||||||
commands =
|
commands =
|
||||||
pip install git+https://github.com/mongodb/mongo-python-driver.git@master
|
pip install git+https://github.com/mongodb/mongo-python-driver.git@master
|
||||||
pip install --pre pymongocrypt
|
pip install --pre pymongocrypt
|
||||||
python --version
|
python --version
|
||||||
python -c "import pymongo; print('PyMongo %s' % (pymongo.version,))"
|
python -c "import pymongo; print('PyMongo %s' % (pymongo.version,))"
|
||||||
python setup.py test --xunit-output=xunit-results {posargs}
|
python -m pytest -v {posargs}
|
||||||
|
|
||||||
[testenv:synchro37]
|
[testenv:synchro]
|
||||||
|
extras =
|
||||||
|
test
|
||||||
|
deps =
|
||||||
|
pynose
|
||||||
allowlist_externals =
|
allowlist_externals =
|
||||||
git
|
git
|
||||||
setenv =
|
setenv =
|
||||||
PYTHONPATH = {envtmpdir}/mongo-python-driver
|
PYTHONPATH = {envtmpdir}/mongo-python-driver
|
||||||
|
# TODO: Remove as part of MOTOR-1163
|
||||||
|
AIOHTTP_NO_EXTENSIONS=1
|
||||||
commands =
|
commands =
|
||||||
git clone --depth 1 --branch master https://github.com/mongodb/mongo-python-driver.git {envtmpdir}/mongo-python-driver
|
git clone --depth 1 --branch master https://github.com/mongodb/mongo-python-driver.git {envtmpdir}/mongo-python-driver
|
||||||
python3 -m pip install -e {envtmpdir}/mongo-python-driver
|
python3 -m pip install -e {envtmpdir}/mongo-python-driver
|
||||||
python3 -m synchro.synchrotest --with-xunit --xunit-file=xunit-synchro-results -v -w {envtmpdir}/mongo-python-driver {posargs}
|
python3 -m synchro.synchrotest --with-xunit --xunit-file=xunit-synchro-results -v -w {envtmpdir}/mongo-python-driver {posargs}
|
||||||
|
|
||||||
[testenv:synchro312]
|
|
||||||
allowlist_externals =
|
|
||||||
git
|
|
||||||
setenv =
|
|
||||||
PYTHONPATH = {envtmpdir}/mongo-python-driver
|
|
||||||
commands =
|
|
||||||
git clone --depth 1 --branch master https://github.com/mongodb/mongo-python-driver.git {envtmpdir}/mongo-python-driver
|
|
||||||
python3 -m pip install -e {envtmpdir}/mongo-python-driver
|
|
||||||
python3 -m synchro.synchrotest -v -w {envtmpdir}/mongo-python-driver {posargs}
|
|
||||||
|
|
||||||
[testenv:lint]
|
[testenv:lint]
|
||||||
deps =
|
deps =
|
||||||
pre-commit
|
pre-commit
|
||||||
commands =
|
commands =
|
||||||
pre-commit run --all-files
|
python -m pre_commit run --all-files
|
||||||
|
|
||||||
|
[testenv:lint-manual]
|
||||||
|
deps =
|
||||||
|
pre-commit
|
||||||
|
commands =
|
||||||
|
python -m pre_commit run --all-files --hook-stage=manual
|
||||||
|
|
||||||
[testenv:manifest]
|
[testenv:manifest]
|
||||||
deps =
|
deps =
|
||||||
check-manifest
|
check-manifest
|
||||||
commands =
|
commands =
|
||||||
check-manifest -v
|
python -m check_manifest -v
|
||||||
|
|
||||||
[gh-actions]
|
|
||||||
# Map GitHub Actions python-version to environment using tox-github-actions.
|
|
||||||
python =
|
|
||||||
3.7: py37
|
|
||||||
3.11: py311,manifest
|
|
||||||
|
|
||||||
[flake8]
|
|
||||||
max-line-length = 100
|
|
||||||
enable-extensions = G
|
|
||||||
extend-ignore =
|
|
||||||
G200, G202, G001
|
|
||||||
# black adds spaces around ':'
|
|
||||||
E203,
|
|
||||||
# E501 line too long (let black handle line length)
|
|
||||||
E501
|
|
||||||
# B305 `.next()` is not a thing on Python 3. Use the `next()` builtin. For Python 2 compatibility, use `six.next()`.
|
|
||||||
B305
|
|
||||||
per-file-ignores =
|
|
||||||
# F841 local variable 'foo' is assigned to but never used
|
|
||||||
# E731 do not assign a lambda expression, use a def
|
|
||||||
# F811 redefinition of unused 'foo' from line XXX
|
|
||||||
test/*/test_examples.py: F841,E731,F811
|
|
||||||
|
|
||||||
# F811 redefinition of unused 'foo' from line XXX
|
|
||||||
# B011 Do not call assert False since python -O removes these calls. Instead callers should raise AssertionError().
|
|
||||||
|
|
||||||
test/*: F811,B011
|
|
||||||
|
|
||||||
# E402 module level import not at top of file
|
|
||||||
doc/examples/monitoring_example.py: E402
|
|
||||||
|
|
||||||
# F403 'from foo import *' used; unable to detect undefined names
|
|
||||||
# F401 'foo' imported but unused
|
|
||||||
synchro/__init__.py: F403,F401
|
|
||||||
|
|
||||||
# F401 'foo' imported but unused
|
|
||||||
motor/__init__.py: F401
|
|
||||||
|
|
||||||
[testenv:typecheck-mypy]
|
[testenv:typecheck-mypy]
|
||||||
description = run mypy to typecheck
|
description = run mypy to typecheck
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user