Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cd98d9b94 | ||
|
|
4fe13c6f25 | ||
|
|
f45226d02f | ||
|
|
c869e5cd7d | ||
|
|
160dbce99f | ||
|
|
2433f62fd9 | ||
|
|
99b56b4633 | ||
|
|
bb744b7b5c | ||
|
|
94a26fa9da | ||
|
|
b3b102a89d | ||
|
|
9bae93d875 | ||
|
|
aab94545dd | ||
|
|
ccc861c5c7 | ||
|
|
87d1c9ed87 | ||
|
|
77bd8ba755 | ||
|
|
61c0e5ccf0 | ||
|
|
156f3b5f16 | ||
|
|
bafa539ed0 | ||
|
|
d0ed67cd80 | ||
|
|
7785176fdc | ||
|
|
536b2dd9d8 | ||
|
|
224da029d5 | ||
|
|
52234081fb | ||
|
|
b81fd4e181 | ||
|
|
820ba59552 | ||
|
|
144c460d8e | ||
|
|
d6c688b609 | ||
|
|
79fd03a68f | ||
|
|
33e4f112c7 | ||
|
|
12d9d7db05 | ||
|
|
5bcdd4ad6a | ||
|
|
5fc7c41fb5 | ||
|
|
bbada7dace | ||
|
|
4bb5e32e80 | ||
|
|
8412d20e28 | ||
|
|
4f1962faf2 | ||
|
|
edcae5440d | ||
|
|
71c3cf9dda | ||
|
|
1b2e255218 | ||
|
|
c734a3a3f6 | ||
|
|
e20ae5fe5b | ||
|
|
f6a70b8c3c | ||
|
|
83f735ad45 | ||
|
|
c291853a13 | ||
|
|
d5d0995776 | ||
|
|
eae1d25c5b | ||
|
|
a879ce528a | ||
|
|
6751d66ed3 | ||
|
|
0c8a698fa4 | ||
|
|
e036c6382d | ||
|
|
e2e967b610 | ||
|
|
9491e32850 | ||
|
|
251d2a088c | ||
|
|
381fdfbde0 | ||
|
|
9cf90a8898 | ||
|
|
0259b9f5a8 | ||
|
|
932bb7382e | ||
|
|
1433773db4 | ||
|
|
459760f4b4 | ||
|
|
b9547fa9c2 | ||
|
|
b4f887bf95 | ||
|
|
c1df3a2105 | ||
|
|
777d2aadf8 | ||
|
|
5cd704ea74 | ||
|
|
a98698531a | ||
|
|
ff9932ce6f | ||
|
|
cbef587966 | ||
|
|
66658d962e | ||
|
|
20015b458e | ||
|
|
cf7b4cfe53 | ||
|
|
e13888b08e | ||
|
|
5c77c38016 | ||
|
|
2a9225d0ce | ||
|
|
7050d54dc4 | ||
|
|
b652685be4 | ||
|
|
48f34cbe02 | ||
|
|
a08b1aff9c | ||
|
|
00f27f3294 | ||
|
|
99cc1b5155 | ||
|
|
633153954d | ||
|
|
972b7ffef9 | ||
|
|
72e68b7569 | ||
|
|
feb49a882c | ||
|
|
cc6dfabdde |
@ -54,21 +54,18 @@ functions:
|
||||
|
||||
export MONGO_ORCHESTRATION_HOME="$DRIVERS_TOOLS/.evergreen/orchestration"
|
||||
export MONGODB_BINARIES="$DRIVERS_TOOLS/mongodb/bin"
|
||||
export UPLOAD_BUCKET="${project}"
|
||||
|
||||
cat <<EOT > expansion.yml
|
||||
CURRENT_VERSION: "$CURRENT_VERSION"
|
||||
DRIVERS_TOOLS: "$DRIVERS_TOOLS"
|
||||
MONGO_ORCHESTRATION_HOME: "$MONGO_ORCHESTRATION_HOME"
|
||||
MONGODB_BINARIES: "$MONGODB_BINARIES"
|
||||
UPLOAD_BUCKET: "$UPLOAD_BUCKET"
|
||||
PROJECT_DIRECTORY: "$PROJECT_DIRECTORY"
|
||||
PREPARE_SHELL: |
|
||||
set -o errexit
|
||||
export DRIVERS_TOOLS="$DRIVERS_TOOLS"
|
||||
export MONGO_ORCHESTRATION_HOME="$MONGO_ORCHESTRATION_HOME"
|
||||
export MONGODB_BINARIES="$MONGODB_BINARIES"
|
||||
export UPLOAD_BUCKET="$UPLOAD_BUCKET"
|
||||
export PROJECT_DIRECTORY="$PROJECT_DIRECTORY"
|
||||
export TMPDIR="$MONGO_ORCHESTRATION_HOME/db"
|
||||
export PATH="$MONGODB_BINARIES:$PATH"
|
||||
@ -99,58 +96,6 @@ functions:
|
||||
fi
|
||||
echo "{ \"releases\": { \"default\": \"$MONGODB_BINARIES\" }}" > $MONGO_ORCHESTRATION_HOME/orchestration.config
|
||||
|
||||
"upload release":
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
local_file: ${project}.tar.gz
|
||||
remote_file: ${UPLOAD_BUCKET}/${project}-${CURRENT_VERSION}.tar.gz
|
||||
bucket: mciuploads
|
||||
permissions: public-read
|
||||
content_type: ${content_type|application/x-gzip}
|
||||
|
||||
# Upload build artifacts that other tasks may depend on
|
||||
# Note this URL needs to be totally unique, while predictable for the next task
|
||||
# so it can automatically download the artifacts
|
||||
"upload build":
|
||||
# Compress and upload the entire build directory
|
||||
- command: archive.targz_pack
|
||||
params:
|
||||
# Example: mongo_c_driver_releng_9dfb7d741efbca16faa7859b9349d7a942273e43_16_11_08_19_29_52.tar.gz
|
||||
target: "${build_id}.tar.gz"
|
||||
source_dir: ${PROJECT_DIRECTORY}/
|
||||
include:
|
||||
- "./**"
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
local_file: ${build_id}.tar.gz
|
||||
# Example: /mciuploads/${UPLOAD_BUCKET}/gcc49/9dfb7d741efbca16faa7859b9349d7a942273e43/debug-compile-nosasl-nossl/mongo_c_driver_releng_9dfb7d741efbca16faa7859b9349d7a942273e43_16_11_08_19_29_52.tar.gz
|
||||
remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${task_name}/${build_id}.tar.gz
|
||||
bucket: mciuploads
|
||||
permissions: public-read
|
||||
content_type: ${content_type|application/x-gzip}
|
||||
|
||||
"fetch build":
|
||||
- command: shell.exec
|
||||
params:
|
||||
continue_on_err: true
|
||||
script: "set -o xtrace && rm -rf ${PROJECT_DIRECTORY}"
|
||||
- command: s3.get
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${BUILD_NAME}/${build_id}.tar.gz
|
||||
bucket: mciuploads
|
||||
local_file: build.tar.gz
|
||||
- command: shell.exec
|
||||
params:
|
||||
continue_on_err: true
|
||||
# EVG-1105: Use s3.get extract_to: ./
|
||||
script: "set -o xtrace && cd .. && rm -rf ${PROJECT_DIRECTORY} && mkdir ${PROJECT_DIRECTORY}/ && tar xf build.tar.gz -C ${PROJECT_DIRECTORY}/"
|
||||
|
||||
"exec compile script" :
|
||||
- command: shell.exec
|
||||
type: test
|
||||
@ -169,74 +114,10 @@ functions:
|
||||
${PREPARE_SHELL}
|
||||
[ -f ${PROJECT_DIRECTORY}/${file} ] && sh ${PROJECT_DIRECTORY}/${file} || echo "${PROJECT_DIRECTORY}/${file} not available, skipping"
|
||||
|
||||
"upload docs" :
|
||||
- command: shell.exec
|
||||
params:
|
||||
silent: true
|
||||
script: |
|
||||
export AWS_ACCESS_KEY_ID=${aws_key}
|
||||
export AWS_SECRET_ACCESS_KEY=${aws_secret}
|
||||
aws s3 cp ${PROJECT_DIRECTORY}/doc/html s3://mciuploads/${UPLOAD_BUCKET}/docs/${CURRENT_VERSION} --recursive --acl public-read --region us-east-1
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
local_file: ${PROJECT_DIRECTORY}/doc/html/index.html
|
||||
remote_file: ${UPLOAD_BUCKET}/docs/${CURRENT_VERSION}/index.html
|
||||
bucket: mciuploads
|
||||
permissions: public-read
|
||||
content_type: text/html
|
||||
display_name: "Rendered docs"
|
||||
|
||||
"upload coverage" :
|
||||
- command: shell.exec
|
||||
params:
|
||||
silent: true
|
||||
script: |
|
||||
export AWS_ACCESS_KEY_ID=${aws_key}
|
||||
export AWS_SECRET_ACCESS_KEY=${aws_secret}
|
||||
aws s3 cp ${PROJECT_DIRECTORY}/coverage s3://mciuploads/${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/coverage/ --recursive --acl public-read --region us-east-1
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
local_file: ${PROJECT_DIRECTORY}/coverage/index.html
|
||||
remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/coverage/index.html
|
||||
bucket: mciuploads
|
||||
permissions: public-read
|
||||
content_type: text/html
|
||||
display_name: "Coverage Report"
|
||||
|
||||
"upload scan artifacts" :
|
||||
- command: shell.exec
|
||||
type: test
|
||||
params:
|
||||
script: |
|
||||
cd
|
||||
if find ${PROJECT_DIRECTORY}/scan -name \*.html | grep -q html; then
|
||||
(cd ${PROJECT_DIRECTORY}/scan && find . -name index.html -exec echo "<li><a href='{}'>{}</a></li>" \;) >> scan.html
|
||||
else
|
||||
echo "No issues found" > scan.html
|
||||
fi
|
||||
- command: shell.exec
|
||||
params:
|
||||
silent: true
|
||||
script: |
|
||||
export AWS_ACCESS_KEY_ID=${aws_key}
|
||||
export AWS_SECRET_ACCESS_KEY=${aws_secret}
|
||||
aws s3 cp ${PROJECT_DIRECTORY}/scan s3://mciuploads/${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/scan/ --recursive --acl public-read --region us-east-1
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
local_file: ${PROJECT_DIRECTORY}/scan.html
|
||||
remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/scan/index.html
|
||||
bucket: mciuploads
|
||||
permissions: public-read
|
||||
content_type: text/html
|
||||
display_name: "Scan Build Report"
|
||||
|
||||
"upload mo artifacts":
|
||||
- command: ec2.assume_role
|
||||
params:
|
||||
role_arn: ${assume_role_arn}
|
||||
- command: shell.exec
|
||||
params:
|
||||
script: |
|
||||
@ -244,62 +125,27 @@ functions:
|
||||
find $MONGO_ORCHESTRATION_HOME -name \*.log | xargs tar czf mongodb-logs.tar.gz
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
aws_key: ${AWS_ACCESS_KEY_ID}
|
||||
aws_secret: ${AWS_SECRET_ACCESS_KEY}
|
||||
aws_session_token: ${AWS_SESSION_TOKEN}
|
||||
local_file: mongodb-logs.tar.gz
|
||||
remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/logs/${task_id}-${execution}-mongodb-logs.tar.gz
|
||||
bucket: mciuploads
|
||||
remote_file: ${build_variant}/${revision}/${version_id}/${build_id}/logs/${task_id}-${execution}-mongodb-logs.tar.gz
|
||||
bucket: ${aws_bucket}
|
||||
permissions: public-read
|
||||
content_type: ${content_type|application/x-gzip}
|
||||
display_name: "mongodb-logs.tar.gz"
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
aws_key: ${AWS_ACCESS_KEY_ID}
|
||||
aws_secret: ${AWS_SECRET_ACCESS_KEY}
|
||||
aws_session_token: ${AWS_SESSION_TOKEN}
|
||||
local_file: ${DRIVERS_TOOLS}/.evergreen/orchestration/server.log
|
||||
remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/logs/${task_id}-${execution}-orchestration.log
|
||||
bucket: mciuploads
|
||||
remote_file: ${build_variant}/${revision}/${version_id}/${build_id}/logs/${task_id}-${execution}-orchestration.log
|
||||
bucket: ${aws_bucket}
|
||||
permissions: public-read
|
||||
content_type: ${content_type|text/plain}
|
||||
display_name: "orchestration.log"
|
||||
|
||||
"upload working dir":
|
||||
- command: archive.targz_pack
|
||||
params:
|
||||
target: "working-dir.tar.gz"
|
||||
source_dir: ${PROJECT_DIRECTORY}/
|
||||
include:
|
||||
- "./**"
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
local_file: working-dir.tar.gz
|
||||
remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/artifacts/${task_id}-${execution}-working-dir.tar.gz
|
||||
bucket: mciuploads
|
||||
permissions: public-read
|
||||
content_type: ${content_type|application/x-gzip}
|
||||
display_name: "working-dir.tar.gz"
|
||||
- command: archive.targz_pack
|
||||
params:
|
||||
target: "drivers-dir.tar.gz"
|
||||
source_dir: ${DRIVERS_TOOLS}
|
||||
include:
|
||||
- "./**"
|
||||
exclude_files:
|
||||
# Windows cannot read the mongod *.lock files because they are locked.
|
||||
- "*.lock"
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
local_file: drivers-dir.tar.gz
|
||||
remote_file: ${UPLOAD_BUCKET}/${build_variant}/${revision}/${version_id}/${build_id}/artifacts/${task_id}-${execution}-drivers-dir.tar.gz
|
||||
bucket: mciuploads
|
||||
permissions: public-read
|
||||
content_type: ${content_type|application/x-gzip}
|
||||
display_name: "drivers-dir.tar.gz"
|
||||
|
||||
"upload test results":
|
||||
- command: attach.results
|
||||
params:
|
||||
@ -462,8 +308,6 @@ pre:
|
||||
- func: "install dependencies"
|
||||
|
||||
post:
|
||||
# Disabled, causing timeouts
|
||||
# - func: "upload working dir"
|
||||
- func: "upload mo artifacts"
|
||||
- func: "upload test results"
|
||||
- func: "stop mongo-orchestration"
|
||||
@ -502,60 +346,6 @@ tasks:
|
||||
|
||||
# Test tasks {{{
|
||||
|
||||
- name: "test-3.6-standalone"
|
||||
tags: ["3.6", "standalone"]
|
||||
commands:
|
||||
- func: "bootstrap mongo-orchestration"
|
||||
vars:
|
||||
VERSION: "3.6"
|
||||
TOPOLOGY: "server"
|
||||
- func: "run tox"
|
||||
|
||||
- name: "test-3.6-replica_set"
|
||||
tags: ["3.6", "replica_set"]
|
||||
commands:
|
||||
- func: "bootstrap mongo-orchestration"
|
||||
vars:
|
||||
VERSION: "3.6"
|
||||
TOPOLOGY: "replica_set"
|
||||
- func: "run tox"
|
||||
|
||||
- name: "test-3.6-sharded_cluster"
|
||||
tags: ["3.6", "sharded_cluster"]
|
||||
commands:
|
||||
- func: "bootstrap mongo-orchestration"
|
||||
vars:
|
||||
VERSION: "3.6"
|
||||
TOPOLOGY: "sharded_cluster"
|
||||
- func: "run tox"
|
||||
|
||||
- name: "test-4.0-standalone"
|
||||
tags: ["4.0", "standalone"]
|
||||
commands:
|
||||
- func: "bootstrap mongo-orchestration"
|
||||
vars:
|
||||
VERSION: "4.0"
|
||||
TOPOLOGY: "server"
|
||||
- func: "run tox"
|
||||
|
||||
- name: "test-4.0-replica_set"
|
||||
tags: ["4.0", "replica_set"]
|
||||
commands:
|
||||
- func: "bootstrap mongo-orchestration"
|
||||
vars:
|
||||
VERSION: "4.0"
|
||||
TOPOLOGY: "replica_set"
|
||||
- func: "run tox"
|
||||
|
||||
- name: "test-4.0-sharded_cluster"
|
||||
tags: ["4.0", "sharded_cluster"]
|
||||
commands:
|
||||
- func: "bootstrap mongo-orchestration"
|
||||
vars:
|
||||
VERSION: "4.0"
|
||||
TOPOLOGY: "sharded_cluster"
|
||||
- func: "run tox"
|
||||
|
||||
- name: "test-4.2-standalone"
|
||||
tags: ["4.2", "standalone"]
|
||||
commands:
|
||||
@ -799,23 +589,6 @@ tasks:
|
||||
vars:
|
||||
TOX_ENV: doctest
|
||||
|
||||
- name: "assign-pr-reviewer"
|
||||
tags: ["pr"]
|
||||
allowed_requesters: ["patch", "github_pr"]
|
||||
commands:
|
||||
- command: shell.exec
|
||||
type: test
|
||||
params:
|
||||
shell: "bash"
|
||||
working_dir: src
|
||||
script: |
|
||||
${PREPARE_SHELL}
|
||||
set -x
|
||||
export CONFIG=$PROJECT_DIRECTORY/.github/reviewers.txt
|
||||
export SCRIPT="$DRIVERS_TOOLS/.evergreen/github_app/assign-reviewer.sh"
|
||||
bash $SCRIPT -p $CONFIG -h ${github_commit} -o "mongodb" -n "motor"
|
||||
echo '{"results": [{ "status": "PASS", "test_file": "Build", "log_raw": "Test completed" } ]}' > ${PROJECT_DIRECTORY}/test-results.json
|
||||
|
||||
# }}}
|
||||
|
||||
axes:
|
||||
@ -836,18 +609,10 @@ axes:
|
||||
- id: tox-env
|
||||
display_name: "Tox Env RHEL8"
|
||||
values:
|
||||
- id: "test-pypy39"
|
||||
- id: "test-pypy310"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "/opt/python/pypy3.9/bin/python3"
|
||||
- id: "test-py38"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
||||
- id: "test-py39"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
|
||||
PYTHON_BINARY: "/opt/python/pypy3.10/bin/python3"
|
||||
- id: "test-py310"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
@ -860,47 +625,59 @@ axes:
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "/opt/python/3.12/bin/python3"
|
||||
- id: "test-py313"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "/opt/python/3.13/bin/python3"
|
||||
- id: "test-py314"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "/opt/python/3.14/bin/python3"
|
||||
- id: "test-pymongo-4.9"
|
||||
variables:
|
||||
TOX_ENV: "test-pymongo-4.9"
|
||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||
- id: "test-pymongo-4.10"
|
||||
variables:
|
||||
TOX_ENV: "test-pymongo-4.10"
|
||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||
- id: "test-pymongo-4.11"
|
||||
variables:
|
||||
TOX_ENV: "test-pymongo-4.11"
|
||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||
- id: "test-pymongo-latest"
|
||||
variables:
|
||||
TOX_ENV: "test-pymongo-latest"
|
||||
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
||||
- id: "synchro-py38"
|
||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||
- id: "synchro-py310"
|
||||
variables:
|
||||
TOX_ENV: "synchro"
|
||||
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
||||
- id: "synchro-py312"
|
||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||
- id: "synchro-py313"
|
||||
variables:
|
||||
TOX_ENV: "synchro"
|
||||
PYTHON_BINARY: "/opt/python/3.12/bin/python3"
|
||||
PYTHON_BINARY: "/opt/python/3.13/bin/python3"
|
||||
|
||||
- id: tox-env-rhel7
|
||||
display_name: "Tox Env RHEL7"
|
||||
- id: tox-env-rhel8
|
||||
display_name: "Tox Env RHEL8"
|
||||
values:
|
||||
- id: "test"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
|
||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||
|
||||
# Test Python 3.8 only on Mac.
|
||||
# Test Python 3.10 only on Mac.
|
||||
- id: tox-env-osx
|
||||
display_name: "Tox Env OSX"
|
||||
values:
|
||||
- id: "test"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "/Library/Frameworks/Python.framework/Versions/3.8/bin/python3"
|
||||
PYTHON_BINARY: "/Library/Frameworks/Python.framework/Versions/3.10/bin/python3"
|
||||
|
||||
- id: tox-env-win
|
||||
display_name: "Tox Env Windows"
|
||||
values:
|
||||
- id: "test-py38"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "c:/python/Python39/python.exe"
|
||||
- id: "test-py39"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "c:/python/Python39/python.exe"
|
||||
- id: "test-py310"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
@ -913,6 +690,14 @@ axes:
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "c:/python/Python312/python.exe"
|
||||
- id: "test-py313"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "c:/python/Python313/python.exe"
|
||||
- id: "test-py314"
|
||||
variables:
|
||||
TOX_ENV: "test"
|
||||
PYTHON_BINARY: "c:/python/Python314/python.exe"
|
||||
|
||||
- id: os
|
||||
display_name: "Operating System"
|
||||
@ -920,15 +705,12 @@ axes:
|
||||
- id: "rhel8"
|
||||
display_name: "RHEL 8.x"
|
||||
run_on: "rhel84-small"
|
||||
- id: "rhel7"
|
||||
display_name: "RHEL 7.x"
|
||||
run_on: "rhel79-small"
|
||||
- id: "win"
|
||||
display_name: "Windows"
|
||||
run_on: "windows-64-vsMulti-small"
|
||||
- id: "macos-1100"
|
||||
display_name: "macOS 11.00"
|
||||
run_on: "macos-1100"
|
||||
- id: "macos-1400"
|
||||
display_name: "macOS 14.00"
|
||||
run_on: "macos-1400"
|
||||
|
||||
buildvariants:
|
||||
|
||||
@ -943,7 +725,7 @@ buildvariants:
|
||||
# TODO: synchro needs PyMongo's updated SSL test certs,
|
||||
# which may require Motor test suite changes.
|
||||
- os: "*"
|
||||
tox-env: ["synchro-py38", "synchro-py312"]
|
||||
tox-env: ["synchro-py310", "synchro-py313"]
|
||||
ssl: "ssl"
|
||||
tasks:
|
||||
- ".rapid"
|
||||
@ -955,13 +737,12 @@ buildvariants:
|
||||
- ".4.4"
|
||||
- ".4.2"
|
||||
- ".4.0"
|
||||
- ".3.6"
|
||||
|
||||
- matrix_name: "test-rhel7"
|
||||
display_name: "${os}-${tox-env-rhel7}-${ssl}"
|
||||
- matrix_name: "test-rhel8"
|
||||
display_name: "${os}-${tox-env-rhel8}-${ssl}"
|
||||
matrix_spec:
|
||||
os: "rhel7"
|
||||
tox-env-rhel7: "*"
|
||||
os: "rhel8"
|
||||
tox-env-rhel8: "*"
|
||||
ssl: "*"
|
||||
tasks:
|
||||
- ".rapid"
|
||||
@ -992,7 +773,7 @@ buildvariants:
|
||||
- matrix_name: "test-macos"
|
||||
display_name: "${os}-${tox-env-osx}-${ssl}"
|
||||
matrix_spec:
|
||||
os: "macos-1100"
|
||||
os: "macos-1400"
|
||||
tox-env-osx: "*"
|
||||
ssl: "*"
|
||||
tasks:
|
||||
@ -1004,7 +785,7 @@ buildvariants:
|
||||
|
||||
- matrix_name: "enterprise-auth"
|
||||
display_name: "Enterprise Auth-${tox-env}"
|
||||
matrix_spec: {"tox-env": ["synchro-py38", "synchro-py312"], ssl: "ssl"}
|
||||
matrix_spec: {"tox-env": ["synchro-py310", "synchro-py313"], ssl: "ssl"}
|
||||
run_on:
|
||||
- "rhel84-small"
|
||||
tasks:
|
||||
@ -1016,7 +797,7 @@ buildvariants:
|
||||
- "rhel84-small"
|
||||
expansions:
|
||||
TOX_ENV: "docs"
|
||||
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||
tasks:
|
||||
- name: "docs"
|
||||
|
||||
@ -1026,12 +807,6 @@ buildvariants:
|
||||
- "rhel84-small"
|
||||
expansions:
|
||||
TOX_ENV: "doctest"
|
||||
PYTHON_BINARY: "/opt/python/3.8/bin/python3"
|
||||
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
|
||||
tasks:
|
||||
- name: "doctest"
|
||||
|
||||
- name: rhel8-pr-assign-reviewer
|
||||
display_name: Assign PR Reviewer
|
||||
run_on: rhel87-small
|
||||
tasks:
|
||||
- name: "assign-pr-reviewer"
|
||||
|
||||
@ -67,17 +67,12 @@ createvirtualenv () {
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
# Set up a virtualenv and install 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 "$@"
|
||||
}
|
||||
|
||||
run_tox "${@:1}"
|
||||
|
||||
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1 @@
|
||||
* @mongodb/dbx-python
|
||||
24
.github/workflows/codeql.yml
vendored
24
.github/workflows/codeql.yml
vendored
@ -26,7 +26,7 @@ on:
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
name: Analyze ${{ matrix.language }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 360
|
||||
permissions:
|
||||
@ -36,35 +36,41 @@ jobs:
|
||||
packages: read
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: python
|
||||
- language: actions
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@c793b717bc78562f491db7b0e93a3a178b099162 # v4
|
||||
with:
|
||||
languages: python
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: none
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
queries: security-extended
|
||||
config: |
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
- 'test/**'
|
||||
|
||||
- shell: bash
|
||||
if: matrix.language == 'python'
|
||||
run: |
|
||||
pip install -e .
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@c793b717bc78562f491db7b0e93a3a178b099162 # v4
|
||||
with:
|
||||
category: "/language:python"
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
7
.github/workflows/dist.yml
vendored
7
.github/workflows/dist.yml
vendored
@ -24,11 +24,12 @@ jobs:
|
||||
name: "Build Dist"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Install dependencies
|
||||
@ -36,7 +37,7 @@ jobs:
|
||||
- name: Create packages
|
||||
run: python -m build .
|
||||
- name: Store package artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: all-dist-${{ github.run_id }}
|
||||
path: "dist/*"
|
||||
|
||||
60
.github/workflows/release.yml
vendored
60
.github/workflows/release.yml
vendored
@ -3,23 +3,25 @@ name: Release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "The new version to set"
|
||||
required: true
|
||||
following_version:
|
||||
description: "The post (dev) version to set"
|
||||
required: true
|
||||
dry_run:
|
||||
description: "Dry Run?"
|
||||
default: false
|
||||
type: boolean
|
||||
schedule:
|
||||
- cron: '30 5 * * *'
|
||||
|
||||
env:
|
||||
# Changes per repo
|
||||
PRODUCT_NAME: Motor
|
||||
# Changes per branch
|
||||
SILK_ASSET_GROUP: motor
|
||||
EVERGREEN_PROJECT: motor
|
||||
# Constant
|
||||
# inputs will be empty on a scheduled run. so, we only set dry_run
|
||||
# to 'false' when the input is set to 'false'.
|
||||
DRY_RUN: ${{ ! contains(inputs.dry_run, 'false') }}
|
||||
FOLLOWING_VERSION: ${{ inputs.following_version || '' }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@ -28,6 +30,7 @@ defaults:
|
||||
jobs:
|
||||
pre-publish:
|
||||
environment: release
|
||||
if: github.repository_owner == 'mongodb' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
@ -35,21 +38,19 @@ jobs:
|
||||
outputs:
|
||||
version: ${{ steps.pre-publish.outputs.version }}
|
||||
steps:
|
||||
- uses: mongodb-labs/drivers-github-tools/secure-checkout@v2
|
||||
- uses: mongodb-labs/drivers-github-tools/secure-checkout@v3
|
||||
with:
|
||||
app_id: ${{ vars.APP_ID }}
|
||||
private_key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
- uses: mongodb-labs/drivers-github-tools/setup@v2
|
||||
- uses: mongodb-labs/drivers-github-tools/setup@v3
|
||||
with:
|
||||
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
|
||||
aws_region_name: ${{ vars.AWS_REGION_NAME }}
|
||||
aws_secret_id: ${{ secrets.AWS_SECRET_ID }}
|
||||
artifactory_username: ${{ vars.ARTIFACTORY_USERNAME }}
|
||||
- uses: mongodb-labs/drivers-github-tools/python/pre-publish@v2
|
||||
- uses: mongodb-labs/drivers-github-tools/python/pre-publish@v3
|
||||
id: pre-publish
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
dry_run: ${{ inputs.dry_run }}
|
||||
dry_run: ${{ env.DRY_RUN }}
|
||||
|
||||
build-dist:
|
||||
needs: [pre-publish]
|
||||
@ -65,29 +66,50 @@ jobs:
|
||||
|
||||
publish:
|
||||
needs: [build-dist, static-scan]
|
||||
name: Upload release to PyPI
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Download all the dists
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: all-dist-${{ github.run_id }}
|
||||
path: dist/
|
||||
- name: Publish package distributions to TestPyPI
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
skip-existing: true
|
||||
attestations: ${{ env.DRY_RUN }}
|
||||
- name: Publish package distributions to PyPI
|
||||
if: startsWith(env.DRY_RUN, 'false')
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
|
||||
|
||||
post-publish:
|
||||
needs: [publish]
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
attestations: write
|
||||
security-events: write
|
||||
steps:
|
||||
- uses: mongodb-labs/drivers-github-tools/secure-checkout@v2
|
||||
- uses: mongodb-labs/drivers-github-tools/secure-checkout@v3
|
||||
with:
|
||||
app_id: ${{ vars.APP_ID }}
|
||||
private_key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
- uses: mongodb-labs/drivers-github-tools/setup@v2
|
||||
- uses: mongodb-labs/drivers-github-tools/setup@v3
|
||||
with:
|
||||
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
|
||||
aws_region_name: ${{ vars.AWS_REGION_NAME }}
|
||||
aws_secret_id: ${{ secrets.AWS_SECRET_ID }}
|
||||
artifactory_username: ${{ vars.ARTIFACTORY_USERNAME }}
|
||||
- uses: mongodb-labs/drivers-github-tools/python/publish@v2
|
||||
- uses: mongodb-labs/drivers-github-tools/python/post-publish@v3
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
following_version: ${{ inputs.following_version }}
|
||||
following_version: ${{ env.FOLLOWING_VERSION }}
|
||||
product_name: ${{ env.PRODUCT_NAME }}
|
||||
silk_asset_group: ${{ env.SILK_ASSET_GROUP }}
|
||||
evergreen_project: ${{ env.EVERGREEN_PROJECT }}
|
||||
token: ${{ github.token }}
|
||||
dry_run: ${{ inputs.dry_run }}
|
||||
dry_run: ${{ env.DRY_RUN }}
|
||||
|
||||
61
.github/workflows/test-python.yml
vendored
61
.github/workflows/test-python.yml
vendored
@ -19,23 +19,26 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
python-version: ["3.8", "3.12"]
|
||||
os: [ubuntu-latest]
|
||||
python-version: ["3.10", "3.12", "3.14"]
|
||||
fail-fast: false
|
||||
name: CPython ${{ matrix.python-version }}-${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'pyproject.toml'
|
||||
allow-prereleases: true
|
||||
- name: Start MongoDB with Custom Options
|
||||
run: |
|
||||
mkdir data
|
||||
mongod --fork --dbpath=$(pwd)/data --logpath=$PWD/mongo.log --setParameter enableTestCommands=1
|
||||
- id: setup-mongodb
|
||||
uses: mongodb-labs/drivers-evergreen-tools@master
|
||||
with:
|
||||
version: "8.0"
|
||||
topology: replica_set
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python -m pip install -U pip tox
|
||||
@ -44,12 +47,14 @@ jobs:
|
||||
tox -m test
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
python-version: 3.8
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.10'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'pyproject.toml'
|
||||
- name: Install Python dependencies
|
||||
@ -60,12 +65,14 @@ jobs:
|
||||
tox -m lint-manual
|
||||
|
||||
docs:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
python-version: 3.8
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.10'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'pyproject.toml'
|
||||
- name: Install Python dependencies
|
||||
@ -75,20 +82,22 @@ jobs:
|
||||
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: Start MongoDB
|
||||
uses: supercharge/mongodb-github-action@315db7fe45ac2880b7758f1933e6e5d59afd5e94 # 1.12.1
|
||||
with:
|
||||
mongodb-version: 5.0
|
||||
- name: Run doctest
|
||||
run: tox -m doctest
|
||||
|
||||
release:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
python-version: 3.8
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.10'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'pyproject.toml'
|
||||
- name: Install Python dependencies
|
||||
@ -102,9 +111,11 @@ jobs:
|
||||
name: Typing Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.10"
|
||||
cache: 'pip'
|
||||
|
||||
21
.github/workflows/zizmor.yml
vendored
Normal file
21
.github/workflows/zizmor.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: GitHub Actions Security Analysis with zizmor 🌈
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
|
||||
jobs:
|
||||
zizmor:
|
||||
name: zizmor latest via Cargo
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run zizmor 🌈
|
||||
uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d
|
||||
7
.github/zizmor.yml
vendored
Normal file
7
.github/zizmor.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
rules:
|
||||
unpinned-uses:
|
||||
config:
|
||||
policies:
|
||||
actions/*: ref-pin
|
||||
mongodb-labs/drivers-github-tools/*: ref-pin
|
||||
mongodb-labs/drivers-evergreen-tools: ref-pin
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@ doc/_build/
|
||||
xunit-results
|
||||
xunit-synchro-results
|
||||
.eggs
|
||||
toxenv
|
||||
|
||||
@ -6,6 +6,7 @@ repos:
|
||||
- id: check-added-large-files
|
||||
- id: check-case-conflict
|
||||
- id: check-toml
|
||||
- id: check-json
|
||||
- id: check-yaml
|
||||
exclude: template.yaml
|
||||
- id: debug-statements
|
||||
@ -65,13 +66,11 @@ repos:
|
||||
stages: [manual]
|
||||
|
||||
- repo: https://github.com/sirosen/check-jsonschema
|
||||
rev: 0.27.0
|
||||
rev: 0.29.0
|
||||
hooks:
|
||||
- id: check-jsonschema
|
||||
name: "Check GitHub Workflows"
|
||||
files: ^\.github/workflows/
|
||||
types: [yaml]
|
||||
args: ["--schemafile", "https://json.schemastore.org/github-workflow"]
|
||||
- id: check-github-workflows
|
||||
- id: check-github-actions
|
||||
- id: check-dependabot
|
||||
|
||||
- repo: https://github.com/ariebovenberg/slotscheck
|
||||
rev: v0.17.0
|
||||
|
||||
@ -35,7 +35,7 @@ Python version on your path, and run:
|
||||
tox -m test
|
||||
```
|
||||
|
||||
The doctests pass with Python 3.8+ and a MongoDB 5.0 instance running on
|
||||
The doctests pass with Python 3.10+ and a MongoDB 5.0 instance running on
|
||||
port 27017:
|
||||
|
||||
```bash
|
||||
|
||||
13
README.md
13
README.md
@ -7,6 +7,13 @@
|
||||
|
||||

|
||||
|
||||
> [!WARNING]
|
||||
> As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
> No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
> After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
> We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
> For help transitioning, see the Migrate to PyMongo Async guide: https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/.
|
||||
|
||||
## About
|
||||
|
||||
Motor is a full-featured, non-blocking [MongoDB](http://mongodb.org/)
|
||||
@ -108,8 +115,8 @@ Motor works in all the environments officially supported by Tornado or
|
||||
by asyncio. It requires:
|
||||
|
||||
- Unix (including macOS) or Windows.
|
||||
- [PyMongo](http://pypi.python.org/pypi/pymongo/) >=4.1,<5
|
||||
- Python 3.8+
|
||||
- [PyMongo](http://pypi.python.org/pypi/pymongo/) >=4.9,<5
|
||||
- Python 3.10+
|
||||
|
||||
Optional dependencies:
|
||||
|
||||
@ -185,7 +192,7 @@ ReadTheDocs](https://motor.readthedocs.io/en/stable/examples/index.html).
|
||||
Motor's documentation is on
|
||||
[ReadTheDocs](https://motor.readthedocs.io/en/stable/).
|
||||
|
||||
Build the documentation with Python 3.8+. Install
|
||||
Build the documentation with Python 3.10+. Install
|
||||
[sphinx](http://sphinx.pocoo.org/), [Tornado](http://tornadoweb.org/),
|
||||
and [aiohttp](https://github.com/aio-libs/aiohttp), and do
|
||||
`cd doc; make html`.
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:mod:`motor.aiohttp` - Integrate Motor with the aiohttp web framework
|
||||
=====================================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.aiohttp
|
||||
|
||||
.. automodule:: motor.aiohttp
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
asyncio GridFS Classes
|
||||
======================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_asyncio
|
||||
|
||||
Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorChangeStream`
|
||||
======================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_asyncio
|
||||
|
||||
.. autoclass:: AsyncIOMotorChangeStream
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorClient` -- Connection to MongoDB
|
||||
=========================================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. autoclass:: motor.motor_asyncio.AsyncIOMotorClient
|
||||
:members:
|
||||
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorClientEncryption`
|
||||
==========================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_asyncio
|
||||
|
||||
.. autoclass:: AsyncIOMotorClientEncryption
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorClientSession` -- Sequence of operations
|
||||
=================================================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. autoclass:: motor.motor_asyncio.AsyncIOMotorClientSession
|
||||
:members:
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorCollection`
|
||||
====================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_asyncio
|
||||
|
||||
.. autoclass:: AsyncIOMotorCollection
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorDatabase`
|
||||
==================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_asyncio
|
||||
|
||||
.. autoclass:: AsyncIOMotorDatabase
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorCursor`
|
||||
================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_asyncio
|
||||
|
||||
.. autoclass:: AsyncIOMotorCursor
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
Motor asyncio API
|
||||
=================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. toctree::
|
||||
|
||||
asyncio_motor_client
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_tornado.MotorCursor`
|
||||
=========================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
.. autoclass:: MotorCursor
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
Motor GridFS Classes
|
||||
====================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
Motor Tornado API
|
||||
=================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. toctree::
|
||||
|
||||
motor_client
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_tornado.MotorChangeStream`
|
||||
===============================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
.. autoclass:: MotorChangeStream
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_tornado.MotorClient` -- Connection to MongoDB
|
||||
==================================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
.. autoclass:: MotorClient
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_tornado.MotorClientEncryption`
|
||||
===================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
.. autoclass:: MotorClientEncryption
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_tornado.MotorClientSession` -- Sequence of operations
|
||||
==========================================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
.. autoclass:: motor.motor_tornado.MotorClientSession
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_tornado.MotorCollection`
|
||||
=============================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
.. autoclass:: MotorCollection
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:class:`~motor.motor_tornado.MotorDatabase`
|
||||
===========================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
.. autoclass:: MotorDatabase
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
:mod:`motor.web` - Integrate Motor with the Tornado web framework
|
||||
=================================================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. currentmodule:: motor.web
|
||||
|
||||
.. automodule:: motor.web
|
||||
|
||||
@ -3,6 +3,52 @@ Changelog
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
Motor 3.8.0
|
||||
-----------
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
- Add support for Python 3.14.
|
||||
- Drop support for Python 3.9.
|
||||
|
||||
Motor 3.7.1
|
||||
-----------
|
||||
|
||||
The 3.7.1 release contains only documentation changes.
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
Motor 3.7.0
|
||||
-----------
|
||||
- Add support for PyMongo 4.10.
|
||||
- Drop support for Python 3.8.
|
||||
- Drop support for MongoDB 3.6.
|
||||
|
||||
|
||||
Motor 3.6.1
|
||||
-----------
|
||||
- Add return type to to_list method in stub file.
|
||||
- Fix ability to install pymongo from source while testing.
|
||||
|
||||
Motor 3.6.0
|
||||
-----------
|
||||
- Add support for MongoDB 8.0 and PyMongo 4.9.
|
||||
- The length parameter in :meth:`MotorCursor.to_list` is now optional.
|
||||
|
||||
.. note::
|
||||
|
||||
This is the last planned minor version of Motor. We are sunsetting Motor in favor of native
|
||||
asyncio support in PyMongo 4.9+. We will continue to provide security releases and bug fixes for
|
||||
Motor, but it will not gain new features.
|
||||
|
||||
Motor 3.5.1
|
||||
-----------
|
||||
- Fix runtime behavior of Motor generic class typing, e.g. ``client: AsyncIOMotorClient[Dict[str, Any]]``.
|
||||
@ -195,8 +241,8 @@ Breaking Changes
|
||||
- Comparing two :class:`~motor.motor_tornado.MotorClient` instances now
|
||||
uses a set of immutable properties rather than
|
||||
:attr:`~motor.motor_tornado.MotorClient.address` which can change.
|
||||
- Removed the ``disable_md5`` parameter for :class:`~gridfs.GridFSBucket` and
|
||||
:class:`~gridfs.GridFS`. See :ref:`removed-gridfs-checksum` for details.
|
||||
- Removed the ``disable_md5`` parameter for :class:`~pymongo.GridFSBucket` and
|
||||
:class:`~pymongo.GridFS`. See :ref:`removed-gridfs-checksum` for details.
|
||||
- PyMongoCrypt 1.2.0 or later is now required for client side field level
|
||||
encryption support.
|
||||
|
||||
@ -663,9 +709,9 @@ Highlights include:
|
||||
|
||||
- Complete support for MongoDB 3.4:
|
||||
|
||||
- Unicode aware string comparison using collations. See :ref:`PyMongo's examples for collation <collation-on-operation>`.
|
||||
- Unicode aware string comparison using collations.
|
||||
- :class:`MotorCursor` and :class:`MotorGridOutCursor` have a new attribute :meth:`~MotorCursor.collation`.
|
||||
- Support for the new :class:`~bson.decimal128.Decimal128` BSON type.
|
||||
- Support for the new :class:`~pymongo.decimal128.Decimal128` BSON type.
|
||||
- A new maxStalenessSeconds read preference option.
|
||||
- A username is no longer required for the MONGODB-X509 authentication
|
||||
mechanism when connected to MongoDB >= 3.4.
|
||||
@ -695,8 +741,8 @@ Highlights include:
|
||||
- TLS compression is now explicitly disabled when possible.
|
||||
- The Server Name Indication (SNI) TLS extension is used when possible.
|
||||
- PyMongo's ``bson`` module provides finer control over JSON encoding/decoding
|
||||
with :class:`~bson.json_util.JSONOptions`.
|
||||
- Allow :class:`~bson.code.Code` objects to have a scope of ``None``,
|
||||
with :class:`~pymongo.json_util.JSONOptions`.
|
||||
- Allow :class:`~pymongo.code.Code` objects to have a scope of ``None``,
|
||||
signifying no scope. Also allow encoding Code objects with an empty scope
|
||||
(i.e. ``{}``).
|
||||
|
||||
@ -719,7 +765,7 @@ Motor 1.0
|
||||
Motor now depends on PyMongo 3.3 and later. The move from PyMongo 2 to 3 brings
|
||||
a large number of API changes, read the `the PyMongo 3 changelog`_ carefully.
|
||||
|
||||
.. _the PyMongo 3 changelog: https://pymongo.readthedocs.io/en/stable/changelog.html#changes-in-version-3-0
|
||||
.. _the PyMongo 3 changelog: https://pymongo.readthedocs.io/en/4.0/changelog.html#changes-in-version-3-0
|
||||
|
||||
:class:`MotorReplicaSetClient` is removed
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -816,9 +862,9 @@ The following find/find_one options have been removed:
|
||||
- await_data (use the new ``cursor_type`` option instead)
|
||||
- exhaust (use the new ``cursor_type`` option instead)
|
||||
- as_class (use :meth:`~motor.motor_tornado.MotorCollection.with_options` with
|
||||
:class:`~bson.codec_options.CodecOptions` instead)
|
||||
:class:`~pymongo.codec_options.CodecOptions` instead)
|
||||
- compile_re (BSON regular expressions are always decoded to
|
||||
:class:`~bson.regex.Regex`)
|
||||
:class:`~pymongo.regex.Regex`)
|
||||
|
||||
The following find/find_one options are deprecated:
|
||||
|
||||
@ -1255,8 +1301,7 @@ therefore inheriting
|
||||
`PyMongo 2.7.2's bug fixes <https://jira.mongodb.org/browse/PYTHON/fixforversion/14005>`_
|
||||
and
|
||||
`PyMongo 2.8's bug fixes <https://jira.mongodb.org/browse/PYTHON/fixforversion/14223>`_
|
||||
and `features
|
||||
<https://pymongo.readthedocs.io/en/stable/changelog.html#changes-in-version-2-8>`_.
|
||||
and features.
|
||||
|
||||
Fixes `a connection-pool timeout when waitQueueMultipleMS is set
|
||||
<https://jira.mongodb.org/browse/MOTOR-62>`_ and `two bugs in replica set
|
||||
|
||||
36
doc/conf.py
36
doc/conf.py
@ -4,11 +4,10 @@
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
import os
|
||||
import sys
|
||||
from importlib.metadata import metadata
|
||||
|
||||
sys.path[0:0] = [os.path.abspath("..")]
|
||||
|
||||
from pymongo import version as pymongo_version # noqa: E402
|
||||
|
||||
import motor # noqa: E402
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
@ -74,7 +73,14 @@ pygments_style = "sphinx"
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
# modindex_common_prefix = []
|
||||
|
||||
linkcheck_ignore = [r"http://localhost:\d+"]
|
||||
# Links to release notes in jira give 401 error: unauthorized. MOTOR-1476
|
||||
linkcheck_ignore = [
|
||||
r"http://localhost:\d+",
|
||||
r"https://jira\.mongodb\.org/secure/ReleaseNote\.jspa.*",
|
||||
]
|
||||
|
||||
# Allow for flaky links.
|
||||
linkcheck_retries = 3
|
||||
|
||||
# -- Options for extensions ----------------------------------------------------
|
||||
autoclass_content = "init"
|
||||
@ -124,15 +130,20 @@ from motor import MotorClient
|
||||
|
||||
html_copy_source = False
|
||||
|
||||
# Theme gratefully vendored from CPython source.
|
||||
html_theme = "pydoctheme"
|
||||
html_theme_path = ["."]
|
||||
html_theme_options = {"collapsiblesidebar": True}
|
||||
html_static_path = ["static"]
|
||||
try:
|
||||
import furo # noqa: F401
|
||||
|
||||
html_sidebars = {
|
||||
"index": ["globaltoc.html", "searchbox.html"],
|
||||
}
|
||||
html_theme = "furo"
|
||||
except ImportError:
|
||||
# Theme gratefully vendored from CPython source.
|
||||
html_theme = "pydoctheme"
|
||||
html_theme_path = ["."]
|
||||
html_theme_options = {"collapsiblesidebar": True}
|
||||
html_static_path = ["static"]
|
||||
|
||||
html_sidebars = {
|
||||
"index": ["globaltoc.html", "searchbox.html"],
|
||||
}
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
@ -213,11 +224,10 @@ autodoc_default_options = {
|
||||
"member-order": "groupwise",
|
||||
}
|
||||
|
||||
pymongo_version = metadata("pymongo")["version"]
|
||||
pymongo_inventory = ("https://pymongo.readthedocs.io/en/%s/" % pymongo_version, None)
|
||||
|
||||
intersphinx_mapping = {
|
||||
"bson": pymongo_inventory,
|
||||
"gridfs": pymongo_inventory,
|
||||
"pymongo": pymongo_inventory,
|
||||
"aiohttp": ("http://aiohttp.readthedocs.io/en/stable/", None),
|
||||
"tornado": ("http://www.tornadoweb.org/en/stable/", None),
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
Configuration
|
||||
=============
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
TLS Protocol Version
|
||||
''''''''''''''''''''
|
||||
|
||||
|
||||
@ -18,3 +18,4 @@ The following is a list of people who have contributed to
|
||||
- Steven Silvester
|
||||
- Julius Park
|
||||
- Doeke Buursma
|
||||
- Scott Luu
|
||||
|
||||
@ -2,6 +2,13 @@
|
||||
Developer Guide
|
||||
===============
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
Some explanations for those who would like to contribute to Motor development.
|
||||
|
||||
Compatibility
|
||||
|
||||
@ -4,6 +4,12 @@
|
||||
Differences between Motor and PyMongo
|
||||
=====================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
.. important:: This page describes using Motor with Tornado. Beginning in
|
||||
version 0.5 Motor can also integrate with asyncio instead of Tornado.
|
||||
|
||||
@ -43,8 +49,8 @@ GridFS
|
||||
|
||||
- File-like
|
||||
|
||||
PyMongo's :class:`~gridfs.grid_file.GridIn` and
|
||||
:class:`~gridfs.grid_file.GridOut` strive to act like Python's built-in
|
||||
PyMongo's :class:`~pymongo.grid_file.GridIn` and
|
||||
:class:`~pymongo.grid_file.GridOut` strive to act like Python's built-in
|
||||
file objects, so they can be passed to many functions that expect files.
|
||||
But the I/O methods of :class:`MotorGridIn` and
|
||||
:class:`MotorGridOut` are asynchronous, so they cannot obey the
|
||||
@ -53,7 +59,7 @@ GridFS
|
||||
- Setting properties
|
||||
|
||||
In PyMongo, you can set arbitrary attributes on
|
||||
a :class:`~gridfs.grid_file.GridIn` and they're stored as metadata on
|
||||
a :class:`~pymongo.grid_file.GridIn` and they're stored as metadata on
|
||||
the server, even after the ``GridIn`` is closed::
|
||||
|
||||
fs = gridfs.GridFSBucket(db)
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
AIOHTTPGridFS Example
|
||||
=====================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
Serve pre-compressed static content from GridFS over HTTP. Uses the `aiohttp`_
|
||||
web framework and :class:`~motor.aiohttp.AIOHTTPGridFS`.
|
||||
|
||||
|
||||
@ -3,6 +3,13 @@
|
||||
Authentication With Motor
|
||||
=========================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
This page describes using Motor with Tornado. Beginning in
|
||||
version 0.5 Motor can also integrate with asyncio instead of Tornado.
|
||||
|
||||
|
||||
@ -5,6 +5,13 @@
|
||||
Bulk Write Operations
|
||||
=====================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
.. testsetup::
|
||||
|
||||
client = MotorClient()
|
||||
|
||||
@ -3,6 +3,13 @@
|
||||
Client-Side Field Level Encryption
|
||||
==================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
Starting in MongoDB 4.2, client-side field level encryption allows an application
|
||||
to encrypt specific data fields in addition to pre-existing MongoDB
|
||||
encryption features such as `Encryption at Rest
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
Motor Examples
|
||||
==============
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
.. seealso:: :doc:`../tutorial-tornado`
|
||||
|
||||
.. toctree::
|
||||
@ -12,5 +19,7 @@ Motor Examples
|
||||
authentication
|
||||
aiohttp_gridfs_example
|
||||
encryption
|
||||
timeouts
|
||||
type_hints
|
||||
|
||||
See also :ref:`example-web-application-aiohttp`.
|
||||
|
||||
@ -3,6 +3,13 @@
|
||||
Application Performance Monitoring (APM)
|
||||
========================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
Motor implements the same `Command Monitoring`_ and `Topology Monitoring`_ specifications as other MongoDB drivers.
|
||||
Therefore, you can register callbacks to be notified of every MongoDB query or command your program sends, and the server's reply to each, as well as getting a notification whenever the driver checks a server's status or detects a change in your replica set.
|
||||
|
||||
|
||||
@ -3,6 +3,13 @@
|
||||
Motor Tailable Cursor Example
|
||||
=============================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
By default, MongoDB will automatically close a cursor when the client has
|
||||
exhausted all results in the cursor. However, for capped collections you may
|
||||
use a tailable cursor that remains open after the client exhausts the results
|
||||
|
||||
87
doc/examples/timeouts.rst
Normal file
87
doc/examples/timeouts.rst
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
.. _timeout-example:
|
||||
|
||||
Client Side Operation Timeout
|
||||
=============================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
PyMongo 4.2 introduced :meth:`~pymongo.timeout` and the ``timeoutMS``
|
||||
URI and keyword argument to :class:`~pymongo.mongo_client.MongoClient`.
|
||||
These features allow applications to more easily limit the amount of time that
|
||||
one or more operations can execute before control is returned to the app. This
|
||||
timeout applies to all of the work done to execute the operation, including
|
||||
but not limited to server selection, connection checkout, serialization, and
|
||||
server-side execution.
|
||||
|
||||
:meth:`~pymongo.timeout` is asyncio safe; the timeout only applies to current
|
||||
Task and multiple Tasks can configure different timeouts concurrently.
|
||||
:meth:`~pymongo.timeout` can be used identically in Motor 3.1+.
|
||||
|
||||
For more information and troubleshooting, see the PyMongo docs on
|
||||
`Client Side Operation Timeout`_.
|
||||
|
||||
.. _Client Side Operation Timeout: https://pymongo.readthedocs.io/en/stable/examples/timeouts.html
|
||||
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
The following example uses :meth:`~pymongo.timeout` to configure a 10-second
|
||||
timeout for an :meth:`~pymongo.collection.Collection.insert_one` operation::
|
||||
|
||||
import pymongo
|
||||
import motor.motor_asyncio
|
||||
client = motor.motor_asyncio.AsyncIOMotorClient()
|
||||
coll = client.test.test
|
||||
with pymongo.timeout(10):
|
||||
await coll.insert_one({"name": "Nunu"})
|
||||
|
||||
The :meth:`~pymongo.timeout` applies to all pymongo operations within the block.
|
||||
The following example ensures that both the ``insert`` and the ``find`` complete
|
||||
within 10 seconds total, or raise a timeout error::
|
||||
|
||||
with pymongo.timeout(10):
|
||||
await coll.insert_one({"name": "Nunu"})
|
||||
await coll.find_one({"name": "Nunu"})
|
||||
|
||||
When nesting :func:`~pymongo.timeout`, the nested deadline is capped by the outer
|
||||
deadline. The deadline can only be shortened, not extended.
|
||||
When exiting the block, the previous deadline is restored::
|
||||
|
||||
with pymongo.timeout(5):
|
||||
await coll.find_one() # Uses the 5 second deadline.
|
||||
with pymongo.timeout(3):
|
||||
await coll.find_one() # Uses the 3 second deadline.
|
||||
await coll.find_one() # Uses the original 5 second deadline.
|
||||
with pymongo.timeout(10):
|
||||
await coll.find_one() # Still uses the original 5 second deadline.
|
||||
await coll.find_one() # Uses the original 5 second deadline.
|
||||
|
||||
Timeout errors
|
||||
--------------
|
||||
|
||||
When the :meth:`~pymongo.timeout` with-statement is entered, a deadline is set
|
||||
for the entire block. When that deadline is exceeded, any blocking pymongo operation
|
||||
will raise a timeout exception. For example::
|
||||
|
||||
try:
|
||||
with pymongo.timeout(10):
|
||||
await coll.insert_one({"name": "Nunu"})
|
||||
await asyncio.sleep(10)
|
||||
# The deadline has now expired, the next operation will raise
|
||||
# a timeout exception.
|
||||
await coll.find_one({"name": "Nunu"})
|
||||
except PyMongoError as exc:
|
||||
if exc.timeout:
|
||||
print(f"block timed out: {exc!r}")
|
||||
else:
|
||||
print(f"failed with non-timeout error: {exc!r}")
|
||||
|
||||
The :attr:`pymongo.errors.PyMongoError.timeout` property (added in PyMongo 4.2)
|
||||
will be ``True`` when the error was caused by a timeout and ``False`` otherwise.
|
||||
@ -3,6 +3,13 @@
|
||||
Tornado Change Stream Example
|
||||
=============================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
Watch a collection for changes with :meth:`MotorCollection.watch` and display
|
||||
|
||||
393
doc/examples/type_hints.rst
Normal file
393
doc/examples/type_hints.rst
Normal file
@ -0,0 +1,393 @@
|
||||
|
||||
.. _type_hints-example:
|
||||
|
||||
Type Hints
|
||||
==========
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
As of version 3.3.0, Motor ships with `type hints`_. With type hints, Python
|
||||
type checkers can easily find bugs before they reveal themselves in your code.
|
||||
|
||||
If your IDE is configured to use type hints,
|
||||
it can suggest more appropriate completions and highlight errors in your code.
|
||||
Some examples include `PyCharm`_, `Sublime Text`_, and `Visual Studio Code`_.
|
||||
|
||||
You can also use the `mypy`_ tool from your command line or in Continuous Integration tests.
|
||||
|
||||
All of the public APIs in Motor are fully type hinted, and
|
||||
several of them support generic parameters for the
|
||||
type of document object returned when decoding BSON documents.
|
||||
|
||||
Due to `limitations in mypy`_, the default
|
||||
values for generic document types are not yet provided (they will eventually be ``Dict[str, any]``).
|
||||
|
||||
For a larger set of examples that use types, see the Motor `test_typing module`_.
|
||||
|
||||
If you would like to opt out of using the provided types, add the following to
|
||||
your `mypy config`_: ::
|
||||
|
||||
[mypy-motor]
|
||||
follow_imports = False
|
||||
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
Note that a type for :class:`~motor.motor_asyncio.AsyncIOMotorClient` must be specified. Here we use the
|
||||
default, unspecified document type:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
collection = client.test.test
|
||||
inserted = await collection.insert_one({"x": 1, "tags": ["dog", "cat"]})
|
||||
retrieved = await collection.find_one({"x": 1})
|
||||
assert isinstance(retrieved, dict)
|
||||
|
||||
For a more accurate typing for document type you can use:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import Any, Dict
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient[Dict[str, Any]] = AsyncIOMotorClient()
|
||||
collection = client.test.test
|
||||
inserted = await collection.insert_one({"x": 1, "tags": ["dog", "cat"]})
|
||||
retrieved = await collection.find_one({"x": 1})
|
||||
assert isinstance(retrieved, dict)
|
||||
|
||||
Typed Client
|
||||
------------
|
||||
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorClient` is generic on the document type used to decode BSON documents.
|
||||
|
||||
You can specify a :class:`~pymongo.raw_bson.RawBSONDocument` document type:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from bson.raw_bson import RawBSONDocument
|
||||
|
||||
|
||||
async def main():
|
||||
client = AsyncIOMotorClient(document_class=RawBSONDocument)
|
||||
collection = client.test.test
|
||||
inserted = await collection.insert_one({"x": 1, "tags": ["dog", "cat"]})
|
||||
result = await collection.find_one({"x": 1})
|
||||
assert isinstance(result, RawBSONDocument)
|
||||
|
||||
Subclasses of :py:class:`collections.abc.Mapping` can also be used, such as :class:`~pymongo.son.SON`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from bson import SON
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
|
||||
|
||||
async def main():
|
||||
client = AsyncIOMotorClient(document_class=SON[str, int])
|
||||
collection = client.test.test
|
||||
inserted = await collection.insert_one({"x": 1, "y": 2})
|
||||
result = await collection.find_one({"x": 1})
|
||||
assert result is not None
|
||||
assert result["x"] == 1
|
||||
|
||||
Note that when using :class:`~pymongo.son.SON`, the key and value types must be given, e.g. ``SON[str, Any]``.
|
||||
|
||||
|
||||
Typed Collection
|
||||
----------------
|
||||
|
||||
You can use :py:class:`~typing.TypedDict` when using a well-defined schema for the data in a
|
||||
:class:`~motor.motor_asyncio.AsyncIOMotorClient`. Note that all `schema validation`_ for inserts and updates is done on the server.
|
||||
These methods automatically add an "_id" field.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import TypedDict
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from motor.motor_asyncio import AsyncIOMotorCollection
|
||||
|
||||
|
||||
class Movie(TypedDict):
|
||||
name: str
|
||||
year: int
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
collection: AsyncIOMotorCollection[Movie] = client.test.test
|
||||
inserted = await collection.insert_one(Movie(name="Jurassic Park", year=1993))
|
||||
result = await collection.find_one({"name": "Jurassic Park"})
|
||||
assert result is not None
|
||||
assert result["year"] == 1993
|
||||
# This will raise a type-checking error, despite being present, because it is added by Motor.
|
||||
assert result["_id"] # type:ignore[typeddict-item]
|
||||
|
||||
This same typing scheme works for all of the insert methods (:meth:`~motor.motor_asyncio.AsyncIOMotorCollection.insert_one`,
|
||||
:meth:`~motor.motor_asyncio.AsyncIOMotorCollection.insert_many`, and :meth:`~motor.motor_asyncio.AsyncIOMotorCollection.bulk_write`).
|
||||
For ``bulk_write`` both :class:`~pymongo.operations.InsertOne` and :class:`~pymongo.operations.ReplaceOne` operators are generic.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import TypedDict
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from motor.motor_asyncio import AsyncIOMotorCollection
|
||||
from pymongo.operations import InsertOne
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
collection: AsyncIOMotorCollection[Movie] = client.test.test
|
||||
inserted = await collection.bulk_write(
|
||||
[InsertOne(Movie(name="Jurassic Park", year=1993))]
|
||||
)
|
||||
result = await collection.find_one({"name": "Jurassic Park"})
|
||||
assert result is not None
|
||||
assert result["year"] == 1993
|
||||
# This will raise a type-checking error, despite being present, because it is added by Motor.
|
||||
assert result["_id"] # type:ignore[typeddict-item]
|
||||
|
||||
Modeling Document Types with TypedDict
|
||||
--------------------------------------
|
||||
|
||||
You can use :py:class:`~typing.TypedDict` to model structured data.
|
||||
As noted above, Motor will automatically add an ``_id`` field if it is not present. This also applies to TypedDict.
|
||||
There are three approaches to this:
|
||||
|
||||
1. Do not specify ``_id`` at all. It will be inserted automatically, and can be retrieved at run-time, but will yield a type-checking error unless explicitly ignored.
|
||||
|
||||
2. Specify ``_id`` explicitly. This will mean that every instance of your custom TypedDict class will have to pass a value for ``_id``.
|
||||
|
||||
3. Make use of :py:class:`~typing.NotRequired`. This has the flexibility of option 1, but with the ability to access the ``_id`` field without causing a type-checking error.
|
||||
|
||||
Note: to use :py:class:`~typing.NotRequired` in earlier versions of Python (<3.11), use the ``typing_extensions`` package.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import TypedDict, NotRequired
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from motor.motor_asyncio import AsyncIOMotorCollection
|
||||
from bson import ObjectId
|
||||
|
||||
|
||||
class Movie(TypedDict):
|
||||
name: str
|
||||
year: int
|
||||
|
||||
|
||||
class ExplicitMovie(TypedDict):
|
||||
_id: ObjectId
|
||||
name: str
|
||||
year: int
|
||||
|
||||
|
||||
class NotRequiredMovie(TypedDict):
|
||||
_id: NotRequired[ObjectId]
|
||||
name: str
|
||||
year: int
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
collection: AsyncIOMotorCollection[Movie] = client.test.test
|
||||
inserted = await collection.insert_one(Movie(name="Jurassic Park", year=1993))
|
||||
result = await collection.find_one({"name": "Jurassic Park"})
|
||||
assert result is not None
|
||||
# This will yield a type-checking error, despite being present, because it is added by Motor.
|
||||
assert result["_id"] # type:ignore[typeddict-item]
|
||||
|
||||
collection: AsyncIOMotorCollection[ExplicitMovie] = client.test.test
|
||||
# Note that the _id keyword argument must be supplied
|
||||
inserted = await collection.insert_one(
|
||||
ExplicitMovie(_id=ObjectId(), name="Jurassic Park", year=1993)
|
||||
)
|
||||
result = await collection.find_one({"name": "Jurassic Park"})
|
||||
assert result is not None
|
||||
# This will not raise a type-checking error.
|
||||
assert result["_id"]
|
||||
|
||||
collection: AsyncIOMotorCollection[NotRequiredMovie] = client.test.test
|
||||
# Note the lack of _id, similar to the first example
|
||||
inserted = await collection.insert_one(
|
||||
NotRequiredMovie(name="Jurassic Park", year=1993)
|
||||
)
|
||||
result = await collection.find_one({"name": "Jurassic Park"})
|
||||
assert result is not None
|
||||
# This will not raise a type-checking error, despite not being provided explicitly.
|
||||
assert result["_id"]
|
||||
|
||||
|
||||
Typed Database
|
||||
--------------
|
||||
|
||||
While less common, you could specify that the documents in an entire database
|
||||
match a well-defined schema using :py:class:`~typing.TypedDict`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import TypedDict
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from motor.motor_asyncio import AsyncIOMotorDatabase
|
||||
|
||||
|
||||
class Movie(TypedDict):
|
||||
name: str
|
||||
year: int
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
db: AsyncIOMotorDatabase[Movie] = client.test
|
||||
collection = db.test
|
||||
inserted = await collection.insert_one({"name": "Jurassic Park", "year": 1993})
|
||||
result = await collection.find_one({"name": "Jurassic Park"})
|
||||
assert result is not None
|
||||
assert result["year"] == 1993
|
||||
|
||||
Typed Command
|
||||
-------------
|
||||
When using the :meth:`~motor.motor_asyncio.AsyncIOMotorDatabase.command`, you can specify the document type by providing a custom :class:`~pymongo.codec_options.CodecOptions`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from bson.raw_bson import RawBSONDocument
|
||||
from bson import CodecOptions
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
options = CodecOptions(RawBSONDocument)
|
||||
result = await client.admin.command("ping", codec_options=options)
|
||||
assert isinstance(result, RawBSONDocument)
|
||||
|
||||
Custom :py:class:`collections.abc.Mapping` subclasses and :py:class:`~typing.TypedDict` are also supported.
|
||||
For :py:class:`~typing.TypedDict`, use the form: ``options: CodecOptions[MyTypedDict] = CodecOptions(...)``.
|
||||
|
||||
Typed BSON Decoding
|
||||
-------------------
|
||||
You can specify the document type returned by :mod:`bson` decoding functions by providing :class:`~pymongo.codec_options.CodecOptions`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import Any, Dict
|
||||
from bson import CodecOptions, encode, decode
|
||||
|
||||
|
||||
class MyDict(Dict[str, Any]):
|
||||
pass
|
||||
|
||||
|
||||
def foo(self):
|
||||
return "bar"
|
||||
|
||||
|
||||
options = CodecOptions(document_class=MyDict)
|
||||
doc = {"x": 1, "y": 2}
|
||||
bsonbytes = encode(doc, codec_options=options)
|
||||
rt_document = decode(bsonbytes, codec_options=options)
|
||||
assert rt_document.foo() == "bar"
|
||||
|
||||
:class:`~pymongo.raw_bson.RawBSONDocument` and :py:class:`~typing.TypedDict` are also supported.
|
||||
For :py:class:`~typing.TypedDict`, use the form: ``options: CodecOptions[MyTypedDict] = CodecOptions(...)``.
|
||||
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
Client Type Annotation
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
If you forget to add a type annotation for a :class:`~motor.motor_asyncio.AsyncIOMotorClient` object you may get the following ``mypy`` error:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
|
||||
client = AsyncIOMotorClient() # error: Need type annotation for "client"
|
||||
|
||||
The solution is to annotate the type as ``client: AsyncIOMotorClient`` or ``client: AsyncIOMotorClient[Dict[str, Any]]``. See `Basic Usage`_.
|
||||
|
||||
Incompatible Types
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
If you use the generic form of :class:`~motor.motor_asyncio.AsyncIOMotorClient` you
|
||||
may encounter a ``mypy`` error like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
await client.test.test.insert_many(
|
||||
{"a": 1}
|
||||
) # error: Dict entry 0 has incompatible type "str": "int";
|
||||
# expected "Mapping[str, Any]": "int"
|
||||
|
||||
|
||||
The solution is to use ``client: AsyncIOMotorClient[Dict[str, Any]]`` as used in
|
||||
`Basic Usage`_ .
|
||||
|
||||
Actual Type Errors
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Other times ``mypy`` will catch an actual error, like the following code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
from typing import Mapping
|
||||
|
||||
|
||||
async def main():
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
await client.test.test.insert_one(
|
||||
[{}]
|
||||
) # error: Argument 1 to "insert_one" of "Collection" has
|
||||
# incompatible type "List[Dict[<nothing>, <nothing>]]";
|
||||
# expected "Mapping[str, Any]"
|
||||
|
||||
In this case the solution is to use ``insert_one({})``, passing a document instead of a list.
|
||||
|
||||
Another example is trying to set a value on a :class:`~pymongo.raw_bson.RawBSONDocument`, which is read-only.:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from bson.raw_bson import RawBSONDocument
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
|
||||
|
||||
async def main():
|
||||
client = AsyncIOMotorClient(document_class=RawBSONDocument)
|
||||
coll = client.test.test
|
||||
doc = {"my": "doc"}
|
||||
await coll.insert_one(doc)
|
||||
retrieved = await coll.find_one({"_id": doc["_id"]})
|
||||
assert retrieved is not None
|
||||
assert len(retrieved.raw) > 0
|
||||
retrieved["foo"] = "bar" # error: Unsupported target for indexed assignment
|
||||
# ("RawBSONDocument") [index]
|
||||
|
||||
.. _PyCharm: https://www.jetbrains.com/help/pycharm/type-hinting-in-product.html
|
||||
.. _Visual Studio Code: https://code.visualstudio.com/docs/languages/python
|
||||
.. _Sublime Text: https://github.com/sublimelsp/LSP-pyright
|
||||
.. _type hints: https://docs.python.org/3/library/typing.html
|
||||
.. _mypy: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
|
||||
.. _limitations in mypy: https://github.com/python/mypy/issues/3737
|
||||
.. _mypy config: https://mypy.readthedocs.io/en/stable/config_file.html
|
||||
.. _test_typing module: https://github.com/mongodb/motor/blob/master/test/test_typing.py
|
||||
.. _schema validation: https://www.mongodb.com/docs/manual/core/schema-validation/#when-to-use-schema-validation
|
||||
@ -4,6 +4,13 @@ Motor Features
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
Non-Blocking
|
||||
============
|
||||
Motor is an asynchronous driver for MongoDB. It can be used from Tornado_ or
|
||||
|
||||
@ -4,6 +4,12 @@ Motor: Asynchronous Python driver for MongoDB
|
||||
.. image:: _static/motor.png
|
||||
:align: center
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
About
|
||||
-----
|
||||
|
||||
@ -54,7 +60,7 @@ project.
|
||||
|
||||
Feature Requests / Feedback
|
||||
---------------------------
|
||||
Use our `feedback engine <https://feedback.mongodb.com/forums/924286-drivers>`_
|
||||
Use our `feedback engine <https://feedback.mongodb.com/?category=7548141816650747033>`_
|
||||
to send us feature requests and general feedback about PyMongo.
|
||||
|
||||
Contributing
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
Install Motor from PyPI_ with pip_::
|
||||
|
||||
$ python3 -m pip install motor
|
||||
@ -19,8 +26,8 @@ Motor works in all the environments officially supported by Tornado or by
|
||||
asyncio. It requires:
|
||||
|
||||
* Unix (including macOS) or Windows.
|
||||
* PyMongo_ >=4.1,<5
|
||||
* Python 3.8+
|
||||
* PyMongo_ >=4.9,<5
|
||||
* Python 3.10+
|
||||
|
||||
Optional dependencies:
|
||||
|
||||
@ -34,7 +41,7 @@ dependency can be installed automatically along with Motor::
|
||||
|
||||
similarly,
|
||||
|
||||
`MONGODB-AWS <https://pymongo.readthedocs.io/en/stable/examples/authentication.html#mongodb-aws>`_
|
||||
`MONGODB-AWS <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/security/authentication/aws-iam/#std-label-pymongo-mongodb-aws>`_
|
||||
authentication requires ``aws`` extra dependency::
|
||||
|
||||
$ pip install "motor[aws]"
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
Motor 2.0 Migration Guide
|
||||
=========================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
Motor 2.0 brings a number of changes to Motor 1.0's API. The major version is
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
Motor 3.0 Migration Guide
|
||||
=========================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
.. currentmodule:: motor.motor_tornado
|
||||
|
||||
Motor 3.0 brings a number of changes to Motor 2.0's API. The major version is
|
||||
@ -179,7 +186,7 @@ can be changed to this::
|
||||
``tz_aware`` defaults to ``False``
|
||||
..................................
|
||||
|
||||
``tz_aware``, an argument for :class:`~bson.json_util.JSONOptions`,
|
||||
``tz_aware``, an argument for :class:`~pymongo.json_util.JSONOptions`,
|
||||
now defaults to ``False`` instead of ``True``. ``json_util.loads`` now
|
||||
decodes datetime as naive by default.
|
||||
|
||||
@ -409,10 +416,11 @@ documents in your own code before passing them to PyMongo, and transform
|
||||
incoming documents after receiving them from PyMongo.
|
||||
|
||||
Alternatively, if your application uses the ``SONManipulator`` API to convert
|
||||
custom types to BSON, the :class:`~bson.codec_options.TypeCodec` and
|
||||
:class:`~bson.codec_options.TypeRegistry` APIs may be a suitable alternative.
|
||||
For more information, see the
|
||||
:external:pymongo:doc:`custom type example <examples/custom_type>`.
|
||||
custom types to BSON, the :class:`~pymongo.codec_options.TypeCodec` and
|
||||
:class:`~pymongo.codec_options.TypeRegistry` APIs may be a suitable alternative.
|
||||
For more information, see the `Custom Types documentation`_.
|
||||
|
||||
.. _Custom Types documentation: https://www.mongodb.com/docs/languages/python/pymongo-driver/current/data-formats/custom-types/type-codecs/
|
||||
|
||||
GridFS changes
|
||||
--------------
|
||||
@ -446,13 +454,12 @@ Removed features with no migration path
|
||||
Encoding a UUID raises an error by default
|
||||
..........................................
|
||||
|
||||
The default uuid_representation for :class:`~bson.codec_options.CodecOptions`,
|
||||
:class:`~bson.json_util.JSONOptions`, and
|
||||
The default uuid_representation for :class:`~pymongo.codec_options.CodecOptions`,
|
||||
:class:`~pymongo.json_util.JSONOptions`, and
|
||||
:class:`~motor.motor_tornado.MotorClient` has been changed from
|
||||
:data:`bson.binary.UuidRepresentation.PYTHON_LEGACY` to
|
||||
:data:`bson.binary.UuidRepresentation.UNSPECIFIED`. Attempting to encode a
|
||||
:class:`uuid.UUID` instance to BSON or JSON now produces an error by default.
|
||||
See :ref:`handling-uuid-data-example` for details.
|
||||
|
||||
|
||||
Upgrade to Motor 3.0
|
||||
|
||||
@ -1,14 +1,21 @@
|
||||
Requirements
|
||||
============
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
The current version of Motor requires:
|
||||
|
||||
* CPython 3.8 and later.
|
||||
* PyMongo_ 4.5 and later.
|
||||
* CPython 3.10 and later.
|
||||
* PyMongo_ 4.9 and later.
|
||||
|
||||
Motor can integrate with either Tornado or asyncio.
|
||||
|
||||
The default authentication mechanism for MongoDB 3.0+ is SCRAM-SHA-1.
|
||||
The default authentication mechanism for MongoDB is SCRAM-SHA-1.
|
||||
|
||||
Building the docs requires `sphinx`_.
|
||||
|
||||
@ -37,29 +44,41 @@ Motor and PyMongo
|
||||
+-------------------+-----------------+
|
||||
| 3.3 | 4.5+ |
|
||||
+-------------------+-----------------+
|
||||
| 3.4 | 4.6+ |
|
||||
| 3.4 | 4.5+ |
|
||||
+-------------------+-----------------+
|
||||
| 3.5 | 4.5+ |
|
||||
+-------------------+-----------------+
|
||||
| 3.6 | 4.9 |
|
||||
+-------------------+-----------------+
|
||||
| 3.7 | 4.9+ |
|
||||
+-------------------+-----------------+
|
||||
|
||||
Motor and MongoDB
|
||||
`````````````````
|
||||
|
||||
+---------------------------------------------------------------+
|
||||
| MongoDB Version |
|
||||
+=====================+=====+=====+=====+=====+=====+=====+=====+
|
||||
| | 3.6 | 4.0 | 4.2 | 4.4 | 5.0 | 6.0 | 7.0 |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| Motor Version | 2.5 | Y | Y | Y | Y | Y |**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.0 | Y | Y | Y | Y | Y |**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.1 | Y | Y | Y | Y | Y | Y |**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.2 | Y | Y | Y | Y | Y | Y | Y |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.3 | Y | Y | Y | Y | Y | Y | Y |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.4 | Y | Y | Y | Y | Y | Y | Y |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
+---------------------------------------------------------------------+
|
||||
| MongoDB Version |
|
||||
+=====================+=====+=====+=====+=====+=====+=====+=====+=====+
|
||||
| | 3.6 | 4.0 | 4.2 | 4.4 | 5.0 | 6.0 | 7.0 | 8.0 |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| Motor Version | 2.5 | Y | Y | Y | Y | Y |**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.0 | Y | Y | Y | Y | Y |**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.1 | Y | Y | Y | Y | Y | Y |**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.2 | Y | Y | Y | Y | Y | Y | Y |**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.3 | Y | Y | Y | Y | Y | Y | Y |**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.4 | Y | Y | Y | Y | Y | Y | Y |**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.5 | Y | Y | Y | Y | Y | Y | Y | Y |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.6 | Y | Y | Y | Y | Y | Y | Y | Y |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.7 | N | Y | Y | Y | Y | Y | Y | Y |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
|
||||
There is no relationship between PyMongo and MongoDB version numbers, although
|
||||
the numbers happen to be close or equal in recent releases of PyMongo and MongoDB.
|
||||
@ -67,7 +86,7 @@ Use `the PyMongo compatibility matrix`_ to determine what MongoDB version is
|
||||
supported by PyMongo. Use the compatibility matrix above to determine what
|
||||
MongoDB version Motor supports.
|
||||
|
||||
.. _the PyMongo compatibility matrix: https://mongodb.com/docs/drivers/pymongo#compatibility
|
||||
.. _the PyMongo compatibility matrix: https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/compatibility/
|
||||
|
||||
Motor and Tornado
|
||||
`````````````````
|
||||
@ -102,45 +121,55 @@ Motor 3.1.1 added support for Python 3.11.
|
||||
|
||||
Motor 3.3 added support for Python 3.12.
|
||||
|
||||
Motor 3.5 dropped support for Python 3.7.
|
||||
Motor 3.5 dropped support for Python 3.7 and added support for Python 3.13.
|
||||
|
||||
+---------------------------------------------------------------+
|
||||
| Python Version |
|
||||
+=====================+=====+=====+=====+=====+=====+=====+=====+
|
||||
| | 3.6 | 3.7 | 3.8 | 3.9 | 3.10| 3.11| 3.12|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| Motor Version | 1.0 | Y |**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 1.1 | Y |**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 1.2 | Y | Y |**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 1.3 | Y | Y |**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.0 | Y | Y |**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.1 | Y | Y | Y |**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.2 | Y | Y | Y |**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.3 | Y | Y | Y |**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.4 | Y | Y | Y | Y |**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.5 | Y | Y | Y | Y | Y |**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.0 |**N**| Y | Y | Y | Y |**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.1 |**N**| Y | Y | Y | Y |**Y**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.2 |**N**| Y | Y | Y | Y | Y |**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.3 |**N**| Y | Y | Y | Y | Y |**Y**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.4 |**N**| Y | Y | Y | Y | Y |**Y**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.5 |**N**|**N**| Y | Y | Y | Y |**Y**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
Motor 3.7 dropped support for Python 3.8.
|
||||
|
||||
Motor 3.8 dropped support for Python 3.9 and added support for Python 3.14.
|
||||
|
||||
+---------------------------------------------------------------------------+
|
||||
| Python Version |
|
||||
+=====================+=====+=====+=====+=====+=====+=====+=====+=====+=====+
|
||||
| | 3.6 | 3.7 | 3.8 | 3.9 | 3.10| 3.11| 3.12| 3.13| 3.14|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| Motor Version | 1.0 | Y |**N**|**N**|**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 1.1 | Y |**N**|**N**|**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 1.2 | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 1.3 | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.0 | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.1 | Y | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.2 | Y | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.3 | Y | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.4 | Y | Y | Y | Y |**N**|**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 2.5 | Y | Y | Y | Y | Y |**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.0 |**N**| Y | Y | Y | Y |**N**|**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.1 |**N**| Y | Y | Y | Y | Y |**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.2 |**N**| Y | Y | Y | Y | Y |**N**|**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.3 |**N**| Y | Y | Y | Y | Y | Y |**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.4 |**N**| Y | Y | Y | Y | Y | Y |**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.5 |**N**|**N**| Y | Y | Y | Y | Y |**N**|**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.6 |**N**|**N**| Y | Y | Y | Y | Y | Y |**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.7 |**N**|**N**|**N**| Y | Y | Y | Y | Y |**N**|
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
| | 3.8 |**N**|**N**|**N**|**N**| Y | Y | Y | Y | Y |
|
||||
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
|
||||
Not Supported
|
||||
-------------
|
||||
|
||||
@ -3,6 +3,13 @@
|
||||
Tutorial: Using Motor With :mod:`asyncio`
|
||||
=========================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
.. These setups are redundant because I can't figure out how to make doctest
|
||||
run a common setup *before* the setup for the two groups. A "testsetup:: *"
|
||||
is the obvious answer, but it's run *after* group-specific setup.
|
||||
@ -78,7 +85,9 @@ Motor, like PyMongo, represents data with a 4-level object hierarchy:
|
||||
|
||||
Creating a Client
|
||||
-----------------
|
||||
You typically create a single instance of :class:`~motor.motor_asyncio.AsyncIOMotorClient` at the time your
|
||||
Creating a client is what establishes a connection to MongoDB and tells your
|
||||
app what deployment (i.e. cluster) to connect to. You typically create a single
|
||||
instance of :class:`~motor.motor_asyncio.AsyncIOMotorClient` at the time your
|
||||
application starts up.
|
||||
|
||||
.. doctest:: before-inserting-2000-docs
|
||||
@ -263,7 +272,7 @@ You can apply a sort, limit, or skip to a query before you begin iterating:
|
||||
The cursor does not actually retrieve each document from the server
|
||||
individually; it gets documents efficiently in `large batches`_.
|
||||
|
||||
.. _`large batches`: https://mongodb.com/docs/manual/tutorial/iterate-a-cursor/#cursor-batches
|
||||
.. _`large batches`: https://www.mongodb.com/docs/manual/core/cursors/#cursor-batches
|
||||
|
||||
Counting Documents
|
||||
------------------
|
||||
@ -452,11 +461,9 @@ to an :class:`aiohttp.web.Application`:
|
||||
:start-after: main-start
|
||||
:end-before: main-end
|
||||
|
||||
Note that it is a common mistake to create a new client object for every
|
||||
request; this comes at a dire performance cost. Create the client
|
||||
when your application starts and reuse that one client for the lifetime
|
||||
of the process. You can maintain the client by storing a database handle
|
||||
from the client on your application object, as shown in this example.
|
||||
.. warning:: It is a common mistake to create a new client object for every request; this comes at a dire performance cost.
|
||||
Create the client when your application starts and reuse that one client for the lifetime of the process.
|
||||
You can maintain the client by storing a database handle from the client on your application object, as shown in this example.
|
||||
|
||||
Visit ``localhost:8080/pages/page-one`` and the server responds "Hello!".
|
||||
At ``localhost:8080/pages/page-two`` it responds "Goodbye." At other URLs it
|
||||
|
||||
@ -3,6 +3,13 @@
|
||||
Tutorial: Using Motor With Tornado
|
||||
==================================
|
||||
|
||||
.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the `Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>`_.
|
||||
|
||||
|
||||
.. These setups are redundant because I can't figure out how to make doctest
|
||||
run a common setup *before* the setup for the two groups. A "testsetup:: *"
|
||||
is the obvious answer, but it's run *after* group-specific setup.
|
||||
@ -86,8 +93,9 @@ Motor, like PyMongo, represents data with a 4-level object hierarchy:
|
||||
|
||||
Creating a Client
|
||||
-----------------
|
||||
You typically create a single instance of :class:`MotorClient` at the time your
|
||||
application starts up.
|
||||
Creating a client is what establishes a connection to MongoDB and tells your
|
||||
app what deployment (i.e. cluster) to connect to. You typically create a single
|
||||
instance of :class:`MotorClient` at the time your application starts up.
|
||||
|
||||
.. doctest:: before-inserting-2000-docs
|
||||
|
||||
@ -151,10 +159,10 @@ makes it available to request handlers::
|
||||
def get(self):
|
||||
db = self.settings['db']
|
||||
|
||||
It is a common mistake to create a new client object for every
|
||||
request; **this comes at a dire performance cost**. Create the client
|
||||
when your application starts and reuse that one client for the lifetime
|
||||
of the process, as shown in these examples.
|
||||
.. warning:: It is a common mistake to create a new client object for every
|
||||
request; **this comes at a dire performance cost**. Create the client
|
||||
when your application starts and reuse that one client for the lifetime
|
||||
of the process, as shown in these examples.
|
||||
|
||||
The Tornado :class:`~tornado.httpserver.HTTPServer` class's :meth:`start`
|
||||
method is a simple way to fork multiple web servers and use all of your
|
||||
@ -351,7 +359,7 @@ You can apply a sort, limit, or skip to a query before you begin iterating:
|
||||
The cursor does not actually retrieve each document from the server
|
||||
individually; it gets documents efficiently in `large batches`_.
|
||||
|
||||
.. _`large batches`: https://mongodb.com/docs/manual/tutorial/iterate-a-cursor/#cursor-batches
|
||||
.. _`large batches`: https://www.mongodb.com/docs/manual/core/cursors/#cursor-batches
|
||||
|
||||
Counting Documents
|
||||
------------------
|
||||
|
||||
@ -14,16 +14,16 @@
|
||||
|
||||
"""Version-related data for motor."""
|
||||
import re
|
||||
from typing import List, Tuple, Union
|
||||
from typing import Union
|
||||
|
||||
__version__ = "3.5.1"
|
||||
__version__ = "3.7.2.dev0"
|
||||
|
||||
|
||||
def get_version_tuple(version: str) -> Tuple[Union[int, str], ...]:
|
||||
def get_version_tuple(version: str) -> tuple[Union[int, str], ...]:
|
||||
pattern = r"(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)"
|
||||
match = re.match(pattern, version)
|
||||
if match:
|
||||
parts: List[Union[int, str]] = [int(match[part]) for part in ["major", "minor", "patch"]]
|
||||
parts: list[Union[int, str]] = [int(match[part]) for part in ["major", "minor", "patch"]]
|
||||
if match["rest"]:
|
||||
parts.append(match["rest"])
|
||||
elif re.match(r"\d+.\d+", version):
|
||||
|
||||
@ -27,7 +27,8 @@ from pymongo.change_stream import ChangeStream
|
||||
from pymongo.client_session import ClientSession
|
||||
from pymongo.collection import Collection
|
||||
from pymongo.command_cursor import CommandCursor, RawBatchCommandCursor
|
||||
from pymongo.cursor import _QUERY_OPTIONS, Cursor, RawBatchCursor
|
||||
from pymongo.cursor import Cursor, RawBatchCursor
|
||||
from pymongo.cursor_shared import _QUERY_OPTIONS
|
||||
from pymongo.database import Database
|
||||
from pymongo.driver_info import DriverInfo
|
||||
from pymongo.encryption import ClientEncryption
|
||||
@ -109,6 +110,7 @@ class AgnosticClient(AgnosticBaseProperties):
|
||||
arbiters = ReadOnlyProperty()
|
||||
close = DelegateMethod()
|
||||
__hash__ = DelegateMethod()
|
||||
bulk_write = AsyncRead()
|
||||
drop_database = AsyncCommand().unwrap("MotorDatabase")
|
||||
options = ReadOnlyProperty()
|
||||
get_database = DelegateMethod(doc=docstrings.get_database_doc).wrap(Database)
|
||||
@ -126,6 +128,7 @@ class AgnosticClient(AgnosticBaseProperties):
|
||||
server_info = AsyncRead()
|
||||
topology_description = ReadOnlyProperty()
|
||||
start_session = AsyncCommand(doc=docstrings.start_session_doc).wrap(ClientSession)
|
||||
_connect = AsyncRead()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Create a new connection to a single MongoDB instance at *host:port*.
|
||||
@ -168,6 +171,21 @@ class AgnosticClient(AgnosticBaseProperties):
|
||||
delegate = self.__delegate_class__(*args, **kwargs)
|
||||
super().__init__(delegate)
|
||||
|
||||
warnings.warn(
|
||||
DeprecationWarning(
|
||||
"""Motor is deprecated as of May 14th, 2025,
|
||||
in favor of the GA release of the PyMongo Async API.
|
||||
No new features will be added to Motor,
|
||||
and only bug fixes will be provided until it reaches end of life on May 14th, 2026.
|
||||
After that, only critical bug fixes will be made until final support ends on May 14th, 2027.
|
||||
We strongly recommend migrating to the PyMongo Async API while Motor is still supported.
|
||||
For help transitioning, see the Migrate to PyMongo Async guide here:
|
||||
https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/
|
||||
"""
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
@property
|
||||
def io_loop(self):
|
||||
if self._io_loop is None:
|
||||
@ -224,7 +242,7 @@ class AgnosticClient(AgnosticBaseProperties):
|
||||
to use for the aggregation.
|
||||
- `start_at_operation_time` (optional): If provided, the resulting
|
||||
change stream will only return changes that occurred at or after
|
||||
the specified :class:`~bson.timestamp.Timestamp`. Requires
|
||||
the specified :class:`~pymongo.timestamp.Timestamp`. Requires
|
||||
MongoDB >= 4.0.
|
||||
- `session` (optional): a
|
||||
:class:`~pymongo.client_session.ClientSession`.
|
||||
@ -690,7 +708,7 @@ class AgnosticDatabase(AgnosticBaseProperties):
|
||||
to use for the aggregation.
|
||||
- `start_at_operation_time` (optional): If provided, the resulting
|
||||
change stream will only return changes that occurred at or after
|
||||
the specified :class:`~bson.timestamp.Timestamp`. Requires
|
||||
the specified :class:`~pymongo.timestamp.Timestamp`. Requires
|
||||
MongoDB >= 4.0.
|
||||
- `session` (optional): a
|
||||
:class:`~pymongo.client_session.ClientSession`.
|
||||
@ -768,7 +786,7 @@ class AgnosticDatabase(AgnosticBaseProperties):
|
||||
.. note:: the order of keys in the `command` document is
|
||||
significant (the "verb" must come first), so commands
|
||||
which require multiple keys (e.g. `findandmodify`)
|
||||
should use an instance of :class:`~bson.son.SON` or
|
||||
should use an instance of :class:`~pymongo.son.SON` or
|
||||
a string and kwargs instead of a Python `dict`.
|
||||
|
||||
- `value` (optional): value to use for the command verb when
|
||||
@ -779,7 +797,7 @@ class AgnosticDatabase(AgnosticBaseProperties):
|
||||
read preference configured for the transaction.
|
||||
Otherwise, defaults to
|
||||
:attr:`~pymongo.read_preferences.ReadPreference.PRIMARY`.
|
||||
- `codec_options`: A :class:`~bson.codec_options.CodecOptions`
|
||||
- `codec_options`: A :class:`~pymongo.codec_options.CodecOptions`
|
||||
instance.
|
||||
- `session` (optional): A
|
||||
:class:`MotorClientSession`.
|
||||
@ -1494,7 +1512,7 @@ class AgnosticBaseCursor(AgnosticBase):
|
||||
.. versionchanged:: 2.2
|
||||
Deprecated.
|
||||
|
||||
.. _`large batches`: https://www.mongodb.com/docs/manual/tutorial/iterate-a-cursor/#cursor-batches
|
||||
.. _`large batches`: https://www.mongodb.com/docs/manual/core/cursors/#cursor-batches
|
||||
.. _`gen.coroutine`: http://tornadoweb.org/en/stable/gen.html
|
||||
"""
|
||||
warnings.warn(
|
||||
@ -1618,7 +1636,7 @@ class AgnosticBaseCursor(AgnosticBase):
|
||||
self._framework.call_soon(self.get_io_loop(), functools.partial(callback, None, None))
|
||||
|
||||
@coroutine_annotation
|
||||
def to_list(self, length):
|
||||
def to_list(self, length=None):
|
||||
"""Get a list of documents.
|
||||
|
||||
.. testsetup:: to_list
|
||||
@ -1769,8 +1787,6 @@ class AgnosticCursor(AgnosticBaseCursor):
|
||||
comment = MotorCursorChainingMethod()
|
||||
allow_disk_use = MotorCursorChainingMethod()
|
||||
|
||||
_Cursor__die = AsyncRead()
|
||||
|
||||
def rewind(self):
|
||||
"""Rewind this cursor to its unevaluated state."""
|
||||
self.delegate.rewind()
|
||||
@ -1788,13 +1804,13 @@ class AgnosticCursor(AgnosticBaseCursor):
|
||||
return self.__class__(self.delegate.__deepcopy__(memo), self.collection)
|
||||
|
||||
def _query_flags(self):
|
||||
return self.delegate._Cursor__query_flags
|
||||
return self.delegate._query_flags
|
||||
|
||||
def _data(self):
|
||||
return self.delegate._Cursor__data
|
||||
return self.delegate._data
|
||||
|
||||
def _killed(self):
|
||||
return self.delegate._Cursor__killed
|
||||
return self.delegate._killed
|
||||
|
||||
|
||||
class AgnosticRawBatchCursor(AgnosticCursor):
|
||||
@ -1806,8 +1822,6 @@ class AgnosticCommandCursor(AgnosticBaseCursor):
|
||||
__motor_class_name__ = "MotorCommandCursor"
|
||||
__delegate_class__ = CommandCursor
|
||||
|
||||
_CommandCursor__die = AsyncRead()
|
||||
|
||||
async def try_next(self):
|
||||
"""Advance the cursor without blocking indefinitely.
|
||||
|
||||
@ -1834,10 +1848,10 @@ class AgnosticCommandCursor(AgnosticBaseCursor):
|
||||
return 0
|
||||
|
||||
def _data(self):
|
||||
return self.delegate._CommandCursor__data
|
||||
return self.delegate._data
|
||||
|
||||
def _killed(self):
|
||||
return self.delegate._CommandCursor__killed
|
||||
return self.delegate._killed
|
||||
|
||||
|
||||
class AgnosticRawBatchCommandCursor(AgnosticCommandCursor):
|
||||
@ -1849,25 +1863,25 @@ class _LatentCursor:
|
||||
"""Take the place of a PyMongo CommandCursor until aggregate() begins."""
|
||||
|
||||
alive = True
|
||||
_CommandCursor__data = []
|
||||
_CommandCursor__id = None
|
||||
_CommandCursor__killed = False
|
||||
_CommandCursor__sock_mgr = None
|
||||
_CommandCursor__session = None
|
||||
_CommandCursor__explicit_session = None
|
||||
_data = []
|
||||
_id = None
|
||||
_killed = False
|
||||
_sock_mgr = None
|
||||
_session = None
|
||||
_explicit_session = None
|
||||
cursor_id = None
|
||||
|
||||
def __init__(self, collection):
|
||||
self._CommandCursor__collection = collection.delegate
|
||||
self._collection = collection.delegate
|
||||
|
||||
def _CommandCursor__end_session(self, *args, **kwargs):
|
||||
def _end_session(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def _CommandCursor__die(self, *args, **kwargs):
|
||||
def _die_lock(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def clone(self):
|
||||
return _LatentCursor(self._CommandCursor__collection)
|
||||
return _LatentCursor(self._collection)
|
||||
|
||||
def rewind(self):
|
||||
pass
|
||||
@ -1924,9 +1938,9 @@ class AgnosticLatentCommandCursor(AgnosticCommandCursor):
|
||||
# Return early if the task was cancelled.
|
||||
if original_future.done():
|
||||
return
|
||||
if self.delegate._CommandCursor__data or not self.delegate.alive:
|
||||
if self.delegate._data or not self.delegate.alive:
|
||||
# _get_more is complete.
|
||||
original_future.set_result(len(self.delegate._CommandCursor__data))
|
||||
original_future.set_result(len(self.delegate._data))
|
||||
else:
|
||||
# Send a getMore.
|
||||
future = super()._get_more()
|
||||
|
||||
@ -13,17 +13,12 @@
|
||||
# limitations under the License.
|
||||
|
||||
from asyncio import Future
|
||||
from collections.abc import Callable, Coroutine, Iterable, Mapping, MutableMapping, Sequence
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Coroutine,
|
||||
Generic,
|
||||
Iterable,
|
||||
Mapping,
|
||||
MutableMapping,
|
||||
NoReturn,
|
||||
Optional,
|
||||
Sequence,
|
||||
TypeVar,
|
||||
Union,
|
||||
overload,
|
||||
@ -40,10 +35,11 @@ from bson.raw_bson import RawBSONDocument
|
||||
from pymongo import IndexModel, ReadPreference, WriteConcern
|
||||
from pymongo.change_stream import ChangeStream
|
||||
from pymongo.client_options import ClientOptions
|
||||
from pymongo.client_session import _T, ClientSession, SessionOptions, TransactionOptions
|
||||
from pymongo.collection import Collection, ReturnDocument, _WriteOp # noqa: F401
|
||||
from pymongo.client_session import ClientSession, SessionOptions, TransactionOptions
|
||||
from pymongo.collection import Collection, ReturnDocument # noqa: F401
|
||||
from pymongo.command_cursor import CommandCursor, RawBatchCommandCursor
|
||||
from pymongo.cursor import Cursor, RawBatchCursor, _Hint, _Sort
|
||||
from pymongo.cursor import Cursor, RawBatchCursor
|
||||
from pymongo.cursor_shared import _Hint, _Sort
|
||||
from pymongo.database import Database
|
||||
from pymongo.encryption import ClientEncryption, RewrapManyDataKeyResult
|
||||
from pymongo.encryption_options import RangeOpts
|
||||
@ -52,11 +48,14 @@ from pymongo.read_concern import ReadConcern
|
||||
from pymongo.read_preferences import _ServerMode
|
||||
from pymongo.results import (
|
||||
BulkWriteResult,
|
||||
ClientBulkWriteResult,
|
||||
DeleteResult,
|
||||
InsertManyResult,
|
||||
InsertOneResult,
|
||||
UpdateResult,
|
||||
)
|
||||
from pymongo.synchronous.client_session import _T
|
||||
from pymongo.synchronous.collection import _WriteOp
|
||||
from pymongo.topology_description import TopologyDescription
|
||||
from pymongo.typings import (
|
||||
_Address,
|
||||
@ -121,6 +120,17 @@ class AgnosticClient(AgnosticBaseProperties[_DocumentType]):
|
||||
write_concern: Optional[WriteConcern] = None,
|
||||
read_concern: Optional[ReadConcern] = None,
|
||||
) -> AgnosticDatabase[_DocumentType]: ...
|
||||
async def bulk_write(
|
||||
self,
|
||||
models: Sequence[_WriteOp[_DocumentType]],
|
||||
session: Optional[ClientSession] = None,
|
||||
ordered: bool = True,
|
||||
verbose_results: bool = False,
|
||||
bypass_document_validation: Optional[bool] = None,
|
||||
comment: Optional[Any] = None,
|
||||
let: Optional[Mapping] = None,
|
||||
write_concern: Optional[WriteConcern] = None,
|
||||
) -> ClientBulkWriteResult: ...
|
||||
|
||||
HOST: str
|
||||
|
||||
@ -694,7 +704,7 @@ class AgnosticBaseCursor(AgnosticBase, Generic[_DocumentType]):
|
||||
def next_object(self) -> Any: ...
|
||||
def each(self, callback: Callable) -> None: ...
|
||||
def _each_got_more(self, callback: Callable, future: Any) -> None: ...
|
||||
def to_list(self, length: Union[int, None]) -> Future[list]: ...
|
||||
def to_list(self, length: Optional[int] = ...) -> Future[list[_DocumentType]]: ...
|
||||
def _to_list(
|
||||
self, length: Union[int, None], the_list: list, future: Any, get_more_result: Any
|
||||
) -> None: ...
|
||||
@ -756,8 +766,7 @@ class AgnosticRawBatchCommandCursor(AgnosticCommandCursor[_DocumentType]):
|
||||
|
||||
class _LatentCursor(Generic[_DocumentType]):
|
||||
def __init__(self, collection: AgnosticCollection[_DocumentType]): ...
|
||||
def _CommandCursor__end_session(self, *args: Any, **kwargs: Any) -> None: ...
|
||||
def _CommandCursor__die(self, *args: Any, **kwargs: Any) -> None: ...
|
||||
def _end_session(self, *args: Any, **kwargs: Any) -> None: ...
|
||||
def clone(self) -> _LatentCursor[_DocumentType]: ...
|
||||
def rewind(self) -> _LatentCursor[_DocumentType]: ...
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ read preference, and/or write concern from this :class:`MotorClient`.
|
||||
:Parameters:
|
||||
- `name`: The name of the database - a string.
|
||||
- `codec_options` (optional): An instance of
|
||||
:class:`~bson.codec_options.CodecOptions`. If ``None`` (the
|
||||
:class:`~pymongo.codec_options.CodecOptions`. If ``None`` (the
|
||||
default) the :attr:`codec_options` of this :class:`MotorClient` is
|
||||
used.
|
||||
- `read_preference` (optional): The read preference to use. If
|
||||
@ -66,7 +66,7 @@ based only on the URI in a configuration file.
|
||||
- `default` (optional): the database name to use if no database name
|
||||
was provided in the URI.
|
||||
- `codec_options` (optional): An instance of
|
||||
:class:`~bson.codec_options.CodecOptions`. If ``None`` (the
|
||||
:class:`~pymongo.codec_options.CodecOptions`. If ``None`` (the
|
||||
default) the :attr:`codec_options` of this :class:`MotorClient` is
|
||||
used.
|
||||
- `read_preference` (optional): The read preference to use. If
|
||||
@ -187,7 +187,7 @@ This will print something like::
|
||||
:Returns:
|
||||
An instance of :class:`~pymongo.results.BulkWriteResult`.
|
||||
|
||||
.. seealso:: :ref:`writes-and-ids`
|
||||
.. seealso:: `Writes and ids <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/crud/insert/#overview>`_
|
||||
|
||||
.. note:: `bypass_document_validation` requires server version
|
||||
**>= 3.2**
|
||||
@ -344,7 +344,7 @@ kwargs. So ``{count: collection_name, query: query}`` becomes::
|
||||
.. note:: the order of keys in the `command` document is
|
||||
significant (the "verb" must come first), so commands
|
||||
which require multiple keys (e.g. `findandmodify`)
|
||||
should use an instance of :class:`~bson.son.SON` or
|
||||
should use an instance of :class:`~pymongo.son.SON` or
|
||||
a string and kwargs instead of a Python :class:`dict`.
|
||||
|
||||
- `value` (optional): value to use for the command verb when
|
||||
@ -829,7 +829,7 @@ This prints something like::
|
||||
:Returns:
|
||||
An instance of :class:`~pymongo.results.InsertManyResult`.
|
||||
|
||||
.. seealso:: :ref:`writes-and-ids`
|
||||
.. seealso:: `Writes and ids <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/crud/insert/#overview>`_
|
||||
|
||||
.. note:: `bypass_document_validation` requires server version
|
||||
**>= 3.2**
|
||||
@ -866,7 +866,7 @@ This code outputs the new document's ``_id``::
|
||||
:Returns:
|
||||
- An instance of :class:`~pymongo.results.InsertOneResult`.
|
||||
|
||||
.. seealso:: :ref:`writes-and-ids`
|
||||
.. seealso:: `Writes and ids <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/crud/insert/#overview>`_
|
||||
|
||||
.. note:: `bypass_document_validation` requires server version
|
||||
**>= 3.2**
|
||||
@ -890,7 +890,7 @@ response from the server to the `map reduce command`_.
|
||||
- `reduce`: reduce function (as a JavaScript string)
|
||||
- `out`: output collection name or `out object` (dict). See
|
||||
the `map reduce command`_ documentation for available options.
|
||||
Note: `out` options are order sensitive. :class:`~bson.son.SON`
|
||||
Note: `out` options are order sensitive. :class:`~pymongo.son.SON`
|
||||
can be used to specify multiple options.
|
||||
e.g. SON([('replace', <collection name>), ('db', <database name>)])
|
||||
- `full_response` (optional): if ``True``, return full response to
|
||||
@ -1149,7 +1149,7 @@ Pass a field name and a direction, either
|
||||
|
||||
>>> async def f():
|
||||
... cursor = collection.find().sort("_id", pymongo.DESCENDING)
|
||||
... docs = await cursor.to_list(None)
|
||||
... docs = await cursor.to_list()
|
||||
... print([d["_id"] for d in docs])
|
||||
...
|
||||
>>> IOLoop.current().run_sync(f)
|
||||
@ -1163,7 +1163,7 @@ To sort by multiple fields, pass a list of (key, direction) pairs:
|
||||
... cursor = collection.find().sort(
|
||||
... [("field1", pymongo.ASCENDING), ("field2", pymongo.DESCENDING)]
|
||||
... )
|
||||
... docs = await cursor.to_list(None)
|
||||
... docs = await cursor.to_list()
|
||||
... print([(d["field1"], d["field2"]) for d in docs])
|
||||
...
|
||||
>>> IOLoop.current().run_sync(f)
|
||||
@ -1277,7 +1277,7 @@ started it.
|
||||
where_doc = """Adds a `$where`_ clause to this query.
|
||||
|
||||
The `code` argument must be an instance of :class:`str`
|
||||
:class:`~bson.code.Code` containing a JavaScript expression.
|
||||
:class:`~pymongo.code.Code` containing a JavaScript expression.
|
||||
This expression will be evaluated for each document scanned.
|
||||
Only those documents for which the expression evaluates to *true*
|
||||
will be returned as results. The keyword *this* refers to the object
|
||||
@ -1293,7 +1293,7 @@ if this :class:`~motor.motor_tornado.MotorCursor` has already been used.
|
||||
Only the last call to :meth:`where` applied to a
|
||||
:class:`~motor.motor_tornado.MotorCursor` has any effect.
|
||||
|
||||
.. note:: MongoDB 4.4 drops support for :class:`~bson.code.Code`
|
||||
.. note:: MongoDB 4.4 drops support for :class:`~pymongo.code.Code`
|
||||
with scope variables. Consider using `$expr`_ instead.
|
||||
|
||||
:Parameters:
|
||||
@ -1337,7 +1337,7 @@ gridfs_delete_doc = """Delete a file's metadata and data chunks from a GridFS bu
|
||||
b"data I want to store!")
|
||||
await fs.delete(file_id)
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no file with file_id exists.
|
||||
|
||||
:Parameters:
|
||||
- `file_id`: The _id of the file to be deleted.
|
||||
@ -1361,7 +1361,7 @@ gridfs_download_to_stream_doc = """Downloads the contents of the stored file spe
|
||||
file.seek(0)
|
||||
contents = file.read()
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no file with file_id exists.
|
||||
|
||||
:Parameters:
|
||||
- `file_id`: The _id of the file to be downloaded.
|
||||
@ -1383,7 +1383,7 @@ gridfs_download_to_stream_by_name_doc = """ Write the contents of `filename
|
||||
file = open('myfile','wb')
|
||||
await fs.download_to_stream_by_name("test_file", file)
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no such version of
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no such version of
|
||||
that file exists.
|
||||
|
||||
Raises :exc:`~ValueError` if `filename` is not a string.
|
||||
@ -1419,7 +1419,7 @@ gridfs_open_download_stream_doc = """Opens a stream to read the contents of the
|
||||
grid_out = await fs.open_download_stream(file_id)
|
||||
contents = await grid_out.read()
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no file with file_id exists.
|
||||
|
||||
:Parameters:
|
||||
- `file_id`: The _id of the file to be downloaded.
|
||||
@ -1441,7 +1441,7 @@ gridfs_open_download_stream_by_name_doc = """Opens a stream to read the contents
|
||||
grid_out = await fs.open_download_stream_by_name(file_id)
|
||||
contents = await grid_out.read()
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no such version of
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no such version of
|
||||
that file exists.
|
||||
|
||||
Raises :exc:`~ValueError` filename is not a string.
|
||||
@ -1484,7 +1484,7 @@ gridfs_open_upload_stream_doc = """Opens a stream for writing.
|
||||
|
||||
Returns an instance of :class:`AsyncIOMotorGridIn`.
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no such version of
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no such version of
|
||||
that file exists.
|
||||
Raises :exc:`~ValueError` if `filename` is not a string.
|
||||
|
||||
@ -1528,7 +1528,7 @@ gridfs_open_upload_stream_with_id_doc = """Opens a stream for writing.
|
||||
|
||||
Returns an instance of :class:`AsyncIOMotorGridIn`.
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no such version of
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no such version of
|
||||
that file exists.
|
||||
Raises :exc:`~ValueError` if `filename` is not a string.
|
||||
|
||||
@ -1560,7 +1560,7 @@ gridfs_rename_doc = """Renames the stored file with the specified file_id.
|
||||
|
||||
await fs.rename(file_id, "new_test_name")
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no file with file_id exists.
|
||||
|
||||
:Parameters:
|
||||
- `file_id`: The _id of the file to be renamed.
|
||||
@ -1581,7 +1581,7 @@ gridfs_upload_from_stream_doc = """Uploads a user file to a GridFS bucket.
|
||||
b"data I want to store!",
|
||||
metadata={"contentType": "text/plain"})
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no such version of
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no such version of
|
||||
that file exists.
|
||||
Raises :exc:`~ValueError` if `filename` is not a string.
|
||||
|
||||
@ -1616,7 +1616,7 @@ gridfs_upload_from_stream_with_id_doc = """Uploads a user file to a GridFS bucke
|
||||
b"data I want to store!",
|
||||
metadata={"contentType": "text/plain"})
|
||||
|
||||
Raises :exc:`~gridfs.errors.NoFile` if no such version of
|
||||
Raises :exc:`~pymongo.errors.NoFile` if no such version of
|
||||
that file exists.
|
||||
Raises :exc:`~ValueError` if `filename` is not a string.
|
||||
|
||||
|
||||
@ -15,9 +15,10 @@
|
||||
"""Dynamic class-creation for Motor."""
|
||||
import functools
|
||||
import inspect
|
||||
from typing import Any, Callable, Dict, TypeVar
|
||||
from collections.abc import Callable
|
||||
from typing import Any, TypeVar
|
||||
|
||||
_class_cache: Dict[Any, Any] = {}
|
||||
_class_cache: dict[Any, Any] = {}
|
||||
|
||||
# mypy: ignore-errors
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
from typing import Any, Mapping, MutableMapping, Optional, Union
|
||||
from collections.abc import Mapping, MutableMapping
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from bson import Code, CodecOptions, Timestamp
|
||||
from bson.raw_bson import RawBSONDocument
|
||||
from pymongo.client_session import TransactionOptions
|
||||
from pymongo.cursor import _Hint, _Sort
|
||||
from pymongo.cursor_shared import _Hint, _Sort
|
||||
from pymongo.read_concern import ReadConcern
|
||||
from pymongo.read_preferences import ReadPreference, _ServerMode
|
||||
from pymongo.typings import _CollationIn, _DocumentType, _DocumentTypeArg, _Pipeline
|
||||
|
||||
@ -37,9 +37,6 @@ class AgnosticGridOutCursor(AgnosticCursor):
|
||||
__motor_class_name__ = "MotorGridOutCursor"
|
||||
__delegate_class__ = gridfs.GridOutCursor
|
||||
|
||||
# PyMongo's GridOutCursor inherits __die from Cursor.
|
||||
_Cursor__die = AsyncCommand()
|
||||
|
||||
def next_object(self):
|
||||
"""**DEPRECATED** - Get next GridOut object from cursor."""
|
||||
# Note: the super() call will raise a warning for the deprecation.
|
||||
@ -76,7 +73,7 @@ class AgnosticGridOut:
|
||||
"""Class to read data out of GridFS.
|
||||
|
||||
MotorGridOut supports the same attributes as PyMongo's
|
||||
:class:`~gridfs.grid_file.GridOut`, such as ``_id``, ``content_type``,
|
||||
:class:`~pymongo.grid_file.GridOut`, such as ``_id``, ``content_type``,
|
||||
etc.
|
||||
|
||||
You don't need to instantiate this class directly - use the
|
||||
@ -88,7 +85,6 @@ class AgnosticGridOut:
|
||||
__motor_class_name__ = "MotorGridOut"
|
||||
__delegate_class__ = gridfs.GridOut
|
||||
|
||||
_ensure_file = AsyncCommand()
|
||||
_id = MotorGridOutProperty()
|
||||
aliases = MotorGridOutProperty()
|
||||
chunk_size = MotorGridOutProperty()
|
||||
@ -98,6 +94,7 @@ class AgnosticGridOut:
|
||||
length = MotorGridOutProperty()
|
||||
metadata = MotorGridOutProperty()
|
||||
name = MotorGridOutProperty()
|
||||
_open = AsyncCommand(attr_name="open")
|
||||
read = AsyncRead()
|
||||
readable = DelegateMethod()
|
||||
readchunk = AsyncRead()
|
||||
@ -160,7 +157,7 @@ class AgnosticGridOut:
|
||||
:class:`~motor.MotorGridOut` now opens itself on demand, calling
|
||||
``open`` explicitly is rarely needed.
|
||||
"""
|
||||
return self._framework.chain_return_value(self._ensure_file(), self.get_io_loop(), self)
|
||||
return self._framework.chain_return_value(self._open(), self.get_io_loop(), self)
|
||||
|
||||
def get_io_loop(self):
|
||||
return self.io_loop
|
||||
@ -258,7 +255,7 @@ Metadata set on the file appears as attributes on a
|
||||
arguments include:
|
||||
|
||||
- ``"_id"``: unique ID for this file (default:
|
||||
:class:`~bson.objectid.ObjectId`) - this ``"_id"`` must
|
||||
:class:`~pymongo.objectid.ObjectId`) - this ``"_id"`` must
|
||||
not have already been used for another file
|
||||
|
||||
- ``"filename"``: human name for the file
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
|
||||
import datetime
|
||||
import os
|
||||
from typing import Any, Iterable, Mapping, NoReturn, Optional
|
||||
from collections.abc import Iterable, Mapping
|
||||
from typing import Any, NoReturn, Optional
|
||||
|
||||
from bson import ObjectId
|
||||
from gridfs import DEFAULT_CHUNK_SIZE, GridFSBucket, GridIn, GridOut, GridOutCursor # noqa: F401
|
||||
@ -35,7 +36,6 @@ _SEEK_END = os.SEEK_END
|
||||
class AgnosticGridOutCursor(AgnosticCursor):
|
||||
__motor_class_name__: str
|
||||
__delegate_class__: type[GridOutCursor]
|
||||
async def _Cursor__die(self, synchronous: bool = False) -> None: ...
|
||||
def next_object(self) -> AgnosticGridOutCursor: ...
|
||||
|
||||
class AgnosticGridOut:
|
||||
@ -50,7 +50,7 @@ class AgnosticGridOut:
|
||||
length: int
|
||||
upload_date: datetime.datetime
|
||||
metadata: Optional[Mapping[str, Any]]
|
||||
async def _ensure_file(self) -> None: ...
|
||||
async def _open(self) -> None: ...
|
||||
def close(self) -> None: ...
|
||||
async def read(self, size: int = -1) -> NoReturn: ...
|
||||
def readable(self) -> bool: ...
|
||||
@ -173,7 +173,7 @@ class AgnosticGridFSBucket:
|
||||
chunk_size_bytes: int = ...,
|
||||
write_concern: Optional[WriteConcern] = None,
|
||||
read_preference: Optional[_ServerMode] = None,
|
||||
collection: Optional[AgnosticCollection] = None,
|
||||
collection: Optional[str] = None,
|
||||
) -> None: ...
|
||||
def get_io_loop(self) -> Any: ...
|
||||
def wrap(self, obj: Any) -> Any: ...
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
from typing import Any, Mapping, MutableMapping, Optional, Union
|
||||
from collections.abc import Mapping, MutableMapping
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from bson import Code, CodecOptions, Timestamp
|
||||
from bson.raw_bson import RawBSONDocument
|
||||
from pymongo.client_session import TransactionOptions
|
||||
from pymongo.cursor import _Hint, _Sort
|
||||
from pymongo.cursor_shared import _Hint, _Sort
|
||||
from pymongo.read_concern import ReadConcern
|
||||
from pymongo.read_preferences import ReadPreference, _ServerMode
|
||||
from pymongo.typings import _CollationIn, _DocumentType, _DocumentTypeArg, _Pipeline
|
||||
|
||||
@ -140,6 +140,7 @@ class GridFSHandler(tornado.web.RequestHandler):
|
||||
ims_value = self.request.headers.get("If-Modified-Since")
|
||||
if ims_value is not None:
|
||||
date_tuple = email.utils.parsedate(ims_value)
|
||||
assert date_tuple is not None
|
||||
|
||||
# If our MotorClient is tz-aware, assume the naive ims_value is in
|
||||
# its time zone.
|
||||
|
||||
@ -8,7 +8,7 @@ dynamic = ["version", "dependencies", "optional-dependencies"]
|
||||
description = "Non-blocking MongoDB driver for Tornado or asyncio"
|
||||
readme = "README.md"
|
||||
license = { file = "LICENSE" }
|
||||
requires-python = ">=3.8"
|
||||
requires-python = ">=3.10"
|
||||
authors = [
|
||||
{ name = "A. Jesse Jiryu Davis", email = "jesse@mongodb.com" },
|
||||
]
|
||||
@ -33,13 +33,13 @@ classifiers = [
|
||||
"Typing :: Typed",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"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",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
@ -66,7 +66,7 @@ test = ["requirements/test.txt"]
|
||||
zstd = ["requirements/zstd.txt"]
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.8"
|
||||
python_version = "3.10"
|
||||
strict = true
|
||||
pretty = true
|
||||
show_error_context = true
|
||||
@ -99,11 +99,15 @@ filterwarnings = [
|
||||
"ignore:GridOut property 'aliases' is deprecated and will be removed in PyMongo 5.0:DeprecationWarning",
|
||||
# From older versions aiohttp.
|
||||
"ignore:\"@coroutine\" decorator is deprecated since Python 3.8:DeprecationWarning",
|
||||
"ignore:The loop argument is deprecated since Python 3.8:DeprecationWarning"
|
||||
"ignore:The loop argument is deprecated since Python 3.8:DeprecationWarning",
|
||||
# TODO: Remove both of these in https://jira.mongodb.org/browse/PYTHON-4731
|
||||
"ignore:Unclosed AsyncMongoClient*",
|
||||
"ignore:Unclosed MongoClient*",
|
||||
# Deprecation warning now that Motor is officially deprecated
|
||||
"ignore:Motor is deprecated*",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py38"
|
||||
line-length = 100
|
||||
|
||||
[tool.ruff.lint]
|
||||
|
||||
@ -1 +1 @@
|
||||
pymongo>=4.5,<5
|
||||
pymongo>=4.9,<5.0
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
tornado
|
||||
aiohttp
|
||||
sphinx>=5.3,<8
|
||||
sphinx_rtd_theme>=2,<3
|
||||
sphinx>=5.3,<9
|
||||
sphinx_rtd_theme>=2,<4
|
||||
readthedocs-sphinx-search~=0.3
|
||||
furo==2025.12.19
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
pytest>=7
|
||||
pytest>=9.0.3
|
||||
mockupdb
|
||||
tornado>=5
|
||||
aiohttp!=3.8.6
|
||||
aiohttp>=3.8.7
|
||||
motor[encryption]
|
||||
cffi>=1.17.0rc1;python_version>="3.13"
|
||||
pytest_asyncio
|
||||
|
||||
@ -28,9 +28,8 @@ from typing import Generic, TypeVar
|
||||
# Make e.g. "from pymongo.errors import AutoReconnect" work. Note that
|
||||
# importing * won't pick up underscore-prefixed attrs.
|
||||
from gridfs import *
|
||||
from gridfs import _disallow_transactions
|
||||
from gridfs.errors import *
|
||||
from gridfs.grid_file import (
|
||||
from gridfs.synchronous.grid_file import (
|
||||
_SEEK_CUR,
|
||||
_SEEK_END,
|
||||
_UPLOAD_BUFFER_CHUNKS,
|
||||
@ -57,33 +56,32 @@ from pymongo import (
|
||||
saslprep,
|
||||
server_selectors,
|
||||
server_type,
|
||||
srv_resolver,
|
||||
ssl_support,
|
||||
uri_parser,
|
||||
write_concern,
|
||||
)
|
||||
from pymongo.synchronous import srv_resolver
|
||||
|
||||
# Added for API compat with pymongo.
|
||||
try:
|
||||
from pymongo import _csot
|
||||
except ImportError:
|
||||
pass
|
||||
from pymongo import client_session
|
||||
from pymongo import client_session, synchronous
|
||||
from pymongo.auth import *
|
||||
from pymongo.auth import _build_credentials_tuple, _password_digest
|
||||
from pymongo.client_session import TransactionOptions, _TxnState
|
||||
from pymongo.client_session import TransactionOptions
|
||||
from pymongo.collation import *
|
||||
from pymongo.common import *
|
||||
from pymongo.common import _MAX_END_SESSIONS, _UUID_REPRESENTATIONS
|
||||
from pymongo.compression_support import _have_snappy, _have_zlib, _have_zstd
|
||||
from pymongo.cursor import *
|
||||
from pymongo.cursor import _QUERY_OPTIONS
|
||||
from pymongo.cursor_shared import _QUERY_OPTIONS
|
||||
from pymongo.encryption import *
|
||||
from pymongo.encryption import _MONGOCRYPTD_TIMEOUT_MS, _Encrypter
|
||||
from pymongo.encryption_options import *
|
||||
from pymongo.encryption_options import _HAVE_PYMONGOCRYPT
|
||||
from pymongo.errors import *
|
||||
from pymongo.event_loggers import *
|
||||
from pymongo.helpers import _check_command_response
|
||||
from pymongo.helpers_shared import _SENSITIVE_COMMANDS, _check_command_response
|
||||
from pymongo.lock import _create_lock
|
||||
from pymongo.message import (
|
||||
_COMMAND_OVERHEAD,
|
||||
@ -91,30 +89,32 @@ from pymongo.message import (
|
||||
_gen_find_command,
|
||||
_maybe_add_read_preference,
|
||||
)
|
||||
from pymongo.monitor import *
|
||||
from pymongo.monitoring import *
|
||||
from pymongo.monitoring import _LISTENERS, _SENSITIVE_COMMANDS, _Listeners
|
||||
from pymongo.monitoring import _LISTENERS, _Listeners
|
||||
from pymongo.ocsp_cache import _OCSPCache
|
||||
from pymongo.operations import *
|
||||
from pymongo.periodic_executor import *
|
||||
from pymongo.periodic_executor import _EXECUTORS
|
||||
from pymongo.pool import *
|
||||
from pymongo.pool import _METADATA, Connection, Pool, _PoolClosedError
|
||||
from pymongo.pool import Connection, Pool
|
||||
from pymongo.read_concern import *
|
||||
from pymongo.read_preferences import *
|
||||
from pymongo.read_preferences import _ServerMode
|
||||
from pymongo.results import *
|
||||
from pymongo.results import _WriteResult
|
||||
from pymongo.saslprep import *
|
||||
from pymongo.server import *
|
||||
from pymongo.server_selectors import *
|
||||
from pymongo.settings import *
|
||||
from pymongo.srv_resolver import _resolve, _SrvResolver
|
||||
from pymongo.ssl_support import *
|
||||
from pymongo.topology import *
|
||||
from pymongo.synchronous.client_session import _TxnState
|
||||
from pymongo.synchronous.encryption import _Encrypter
|
||||
from pymongo.synchronous.monitor import *
|
||||
from pymongo.synchronous.pool import _PoolClosedError
|
||||
from pymongo.synchronous.server import *
|
||||
from pymongo.synchronous.settings import *
|
||||
from pymongo.synchronous.srv_resolver import _have_dnspython, _resolve, _SrvResolver
|
||||
from pymongo.synchronous.topology import *
|
||||
from pymongo.topology_description import *
|
||||
from pymongo.uri_parser import *
|
||||
from pymongo.uri_parser import _have_dnspython
|
||||
from pymongo.write_concern import *
|
||||
from tornado.ioloop import IOLoop
|
||||
|
||||
@ -131,6 +131,7 @@ from motor.motor_tornado import create_motor_class
|
||||
|
||||
_MotorRawBatchCursor = create_motor_class(_AgnosticRawBatchCursor)
|
||||
_MotorRawBatchCommandCursor = create_motor_class(_AgnosticRawBatchCommandCursor)
|
||||
get_hosts_and_min_ttl = _SrvResolver.get_hosts_and_min_ttl
|
||||
|
||||
|
||||
def wrap_synchro(fn):
|
||||
@ -262,9 +263,6 @@ class SynchroMeta(type):
|
||||
|
||||
- Motor methods which return Motor class instances are wrapped to return
|
||||
Synchro class instances.
|
||||
|
||||
- Certain internals accessed by PyMongo's unittests, such as _Cursor__data,
|
||||
are delegated from Synchro directly to PyMongo.
|
||||
"""
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
@ -301,7 +299,7 @@ class SynchroMeta(type):
|
||||
|
||||
# Set DelegateProperties' and SynchroProperties' names.
|
||||
for name, attr in attrs.items():
|
||||
if isinstance(attr, (MotorAttributeFactory, SynchroAttr)): # noqa: SIM102
|
||||
if isinstance(attr, (MotorAttributeFactory, SynchroAttr)): # noqa: SIM102,UP038
|
||||
if attr.name is None:
|
||||
attr.name = name
|
||||
|
||||
@ -395,9 +393,10 @@ class MongoClient(Synchro, Generic[_T]):
|
||||
return Database(self, name, delegate=self.delegate[name])
|
||||
|
||||
# For PyMongo tests that access client internals.
|
||||
_MongoClient__all_credentials = SynchroProperty()
|
||||
_MongoClient__kill_cursors_queue = SynchroProperty()
|
||||
_MongoClient__options = SynchroProperty()
|
||||
_connect = Sync()
|
||||
_all_credentials = SynchroProperty()
|
||||
_kill_cursors_queue = SynchroProperty()
|
||||
_options = SynchroProperty()
|
||||
_cache_credentials = SynchroProperty()
|
||||
_close_cursor_now = SynchroProperty()
|
||||
_get_topology = SynchroProperty()
|
||||
@ -577,6 +576,16 @@ class Cursor(Synchro):
|
||||
rewind = WrapOutgoing()
|
||||
clone = WrapOutgoing()
|
||||
close = Sync("close")
|
||||
to_list = Sync("to_list")
|
||||
|
||||
_query_flags = SynchroProperty()
|
||||
_data = SynchroProperty()
|
||||
_max_time_ms = SynchroProperty()
|
||||
_max_await_time_ms = SynchroProperty()
|
||||
_retrieved = SynchroProperty()
|
||||
_spec = SynchroProperty()
|
||||
_exhaust = SynchroProperty()
|
||||
_query_spec = SynchroProperty()
|
||||
|
||||
_next = Sync("next")
|
||||
|
||||
@ -618,22 +627,12 @@ class Cursor(Synchro):
|
||||
# Don't suppress exceptions.
|
||||
return False
|
||||
|
||||
# For PyMongo tests that access cursor internals.
|
||||
_Cursor__data = SynchroProperty()
|
||||
_Cursor__exhaust = SynchroProperty()
|
||||
_Cursor__max_await_time_ms = SynchroProperty()
|
||||
_Cursor__max_time_ms = SynchroProperty()
|
||||
_Cursor__query_flags = SynchroProperty()
|
||||
_Cursor__query_spec = SynchroProperty()
|
||||
_Cursor__retrieved = SynchroProperty()
|
||||
_Cursor__spec = SynchroProperty()
|
||||
_read_preference = SynchroProperty()
|
||||
|
||||
|
||||
class CommandCursor(Cursor):
|
||||
__delegate_class__ = motor.motor_tornado.MotorCommandCursor
|
||||
|
||||
try_next = Sync("try_next")
|
||||
to_list = Sync("to_list")
|
||||
|
||||
|
||||
class GridOutCursor(Cursor):
|
||||
|
||||
@ -197,6 +197,28 @@ excluded_tests = [
|
||||
"TestClient.test_handshake*",
|
||||
# This test is not a valid unittest target.
|
||||
"TestRangeQueryProse.run_test_cases",
|
||||
# The test logic interferes with the SynchroLoader.
|
||||
"ClientUnitTest.test_detected_environment_logging",
|
||||
"ClientUnitTest.test_detected_environment_warning",
|
||||
# The batch_size portion of this test does not work with synchro.
|
||||
"TestCursor.test_to_list_length",
|
||||
# These tests hang due to internal incompatibilities in to_list.
|
||||
"TestCursor.test_command_cursor_to_list*",
|
||||
# Motor does not allow calling to_list on a tailable cursor.
|
||||
"TestCursor.test_max_await_time_ms",
|
||||
"TestCursor.test_to_list_tailable",
|
||||
# This test relies on a private api"
|
||||
"TestTransactions.test_transaction_pool_cleared_error_labelled_transient",
|
||||
# Newer tests not implemented in Motor
|
||||
"TestClient.test_repr_srv_host",
|
||||
"TestGridfs.test_delete_by_name",
|
||||
"TestGridfs.test_rename_by_name",
|
||||
"TestGridfsDeleteByName.*",
|
||||
"TestGridfsRenameByName.*",
|
||||
"TestMongosAndReadPreference.test_read_preference_hedge_deprecated",
|
||||
"TestUnifiedTestFormatValidPassKmsProvidersExplicitKmsCredentials.*",
|
||||
"TestUnifiedTestFormatValidPassKmsProvidersMixedKmsCredentialFields.*",
|
||||
"TestUnifiedTestFormatValidPassKmsProvidersPlaceholderKmsCredentials.*",
|
||||
]
|
||||
|
||||
|
||||
@ -230,11 +252,7 @@ class SynchroModuleFinder(importlib.abc.MetaPathFinder):
|
||||
class SynchroModuleLoader(importlib.abc.Loader):
|
||||
def patch_spec(self, fullname):
|
||||
parts = fullname.split(".")
|
||||
if parts[-1] in ("gridfs", "pymongo"):
|
||||
# E.g. "import pymongo"
|
||||
return True
|
||||
elif len(parts) >= 2 and parts[-2] in ("gridfs", "pymongo"):
|
||||
# E.g. "import pymongo.mongo_client"
|
||||
if ("pymongo" in parts or "gridfs" in parts) and "asynchronous" not in parts:
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -327,9 +345,18 @@ if __name__ == "__main__":
|
||||
"pymongo.encryption_options",
|
||||
"pymongo.mongo_client",
|
||||
"pymongo.database",
|
||||
"pymongo.srv_resolver",
|
||||
"pymongo.synchronous.srv_resolver",
|
||||
"pymongo.synchronous.collection",
|
||||
"pymongo.synchronous.client_session",
|
||||
"pymongo.synchronous.command_cursor",
|
||||
"pymongo.synchronous.change_stream",
|
||||
"pymongo.synchronous.cursor",
|
||||
"pymongo.synchronous.encryption",
|
||||
"pymongo.synchronous.mongo_client",
|
||||
"pymongo.synchronous.database",
|
||||
"gridfs",
|
||||
"gridfs.grid_file",
|
||||
"gridfs.synchronous.grid_file",
|
||||
]:
|
||||
sys.modules.pop(n)
|
||||
|
||||
@ -341,7 +368,13 @@ if __name__ == "__main__":
|
||||
|
||||
# Run the tests from the pymongo target dir with our custom plugin.
|
||||
os.chdir(sys.argv[1])
|
||||
code = pytest.main(sys.argv[2:] + ["-p", "no:warnings"], plugins=[SynchroPytestPlugin()])
|
||||
if "-m" in sys.argv[2:]:
|
||||
markers = []
|
||||
else:
|
||||
markers = ["-m", "default"]
|
||||
code = pytest.main(
|
||||
sys.argv[2:] + markers + ["-p", "no:warnings"], plugins=[SynchroPytestPlugin()]
|
||||
)
|
||||
|
||||
if code != 0:
|
||||
sys.exit(code)
|
||||
|
||||
@ -18,10 +18,22 @@ import asyncio
|
||||
import datetime
|
||||
import email
|
||||
import logging
|
||||
import sys
|
||||
import test
|
||||
import time
|
||||
from test.asyncio_tests import AsyncIOTestCase, asyncio_test
|
||||
|
||||
import pytest
|
||||
|
||||
# MOTOR-1477 - after libzstd is supported on build hosts
|
||||
# we can remove this guard.
|
||||
if sys.version_info >= (3, 14):
|
||||
try:
|
||||
import compression.zstd # noqa: F401
|
||||
except ModuleNotFoundError:
|
||||
pytest.skip(allow_module_level=True)
|
||||
|
||||
|
||||
import aiohttp
|
||||
import aiohttp.web
|
||||
import gridfs
|
||||
|
||||
@ -98,7 +98,7 @@ class AIOMotorTestBasic(AsyncIOTestCase):
|
||||
motor_cursor = collection.find()
|
||||
cursor = motor_cursor.delegate
|
||||
|
||||
self.assertEqual(Nearest(tag_sets=[{"yay": "jesse"}]), cursor._read_preference())
|
||||
self.assertEqual(Nearest(tag_sets=[{"yay": "jesse"}]), cursor._get_read_preference())
|
||||
|
||||
cx.close()
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ from test.asyncio_tests import (
|
||||
remove_all_users,
|
||||
)
|
||||
from test.test_environment import db_password, db_user, env
|
||||
from test.utils import get_primary_pool
|
||||
from test.utils import AUTO_ISMASTER, get_primary_pool
|
||||
|
||||
import pymongo
|
||||
from bson import CodecOptions
|
||||
@ -257,7 +257,7 @@ class TestAsyncIOClient(AsyncIOTestCase):
|
||||
class TestAsyncIOClientTimeout(AsyncIOMockServerTestCase):
|
||||
@asyncio_test
|
||||
async def test_timeout(self):
|
||||
server = self.server(auto_ismaster=True)
|
||||
server = self.server(auto_ismaster=AUTO_ISMASTER)
|
||||
client = motor_asyncio.AsyncIOMotorClient(
|
||||
server.uri, socketTimeoutMS=100, io_loop=self.loop
|
||||
)
|
||||
@ -281,7 +281,7 @@ class TestAsyncIOClientHandshake(AsyncIOMockServerTestCase):
|
||||
future = client.db.command("ping")
|
||||
ismaster = await self.run_thread(server.receives, "ismaster")
|
||||
meta = ismaster.doc["client"]
|
||||
self.assertEqual("PyMongo|Motor", meta["driver"]["name"])
|
||||
self.assertIn("|Motor", meta["driver"]["name"])
|
||||
# AsyncIOMotorClient adds nothing to platform.
|
||||
self.assertNotIn("Tornado", meta["platform"])
|
||||
self.assertTrue(
|
||||
|
||||
@ -270,7 +270,7 @@ class TestAsyncIOCollection(AsyncIOTestCase):
|
||||
@env.require_no_standalone
|
||||
@asyncio_test
|
||||
async def test_async_create_encrypted_collection(self):
|
||||
c = self.collection
|
||||
c = self.cx
|
||||
KMS_PROVIDERS = {"local": {"key": b"\x00" * 96}}
|
||||
self.cx.drop_database("db")
|
||||
async with AsyncIOMotorClientEncryption(
|
||||
@ -287,9 +287,10 @@ class TestAsyncIOCollection(AsyncIOTestCase):
|
||||
self.assertEqual(exc.exception.code, 121)
|
||||
await self.db.drop_collection("testing1", encrypted_fields=ef)
|
||||
|
||||
@env.require_version_min(8, 0, -1, -1)
|
||||
@asyncio_test
|
||||
async def test_async_encrypt_expression(self):
|
||||
c = self.collection
|
||||
c = self.cx
|
||||
KMS_PROVIDERS = {"local": {"key": b"\x00" * 96}}
|
||||
self.cx.drop_database("db")
|
||||
async with AsyncIOMotorClientEncryption(
|
||||
@ -299,12 +300,12 @@ class TestAsyncIOCollection(AsyncIOTestCase):
|
||||
"local", key_alt_names=["pymongo_encryption_example_1"]
|
||||
)
|
||||
name = "DoubleNoPrecision"
|
||||
range_opts = RangeOpts(sparsity=1)
|
||||
range_opts = RangeOpts(sparsity=1, trim_factor=1)
|
||||
for i in [6.0, 30.0, 200.0]:
|
||||
insert_payload = await client_encryption.encrypt(
|
||||
float(i),
|
||||
key_id=data_key,
|
||||
algorithm=Algorithm.RANGEPREVIEW,
|
||||
algorithm=Algorithm.RANGE,
|
||||
contention_factor=0,
|
||||
range_opts=range_opts,
|
||||
)
|
||||
@ -323,8 +324,8 @@ class TestAsyncIOCollection(AsyncIOTestCase):
|
||||
]
|
||||
},
|
||||
key_id=data_key,
|
||||
algorithm=Algorithm.RANGEPREVIEW,
|
||||
query_type=QueryType.RANGEPREVIEW,
|
||||
algorithm=Algorithm.RANGE,
|
||||
query_type=QueryType.RANGE,
|
||||
contention_factor=0,
|
||||
range_opts=range_opts,
|
||||
)
|
||||
@ -333,7 +334,7 @@ class TestAsyncIOCollection(AsyncIOTestCase):
|
||||
await self.collection.explicit_encryption.find(find_payload).to_list(3),
|
||||
key=lambda x: x["_id"],
|
||||
)
|
||||
for elem, expected in zip(sorted_find, [6.0, 30.0, 200.0]):
|
||||
for elem, expected in zip(sorted_find, [6.0, 30.0, 200.0], strict=False):
|
||||
self.assertEqual(elem[f"encrypted{name}"], expected)
|
||||
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ from test.asyncio_tests import (
|
||||
)
|
||||
from test.test_environment import env
|
||||
from test.utils import (
|
||||
AUTO_ISMASTER,
|
||||
FailPoint,
|
||||
TestListener,
|
||||
get_async_test_timeout,
|
||||
@ -86,7 +87,7 @@ class TestAsyncIOCursor(AsyncIOMockServerTestCase):
|
||||
@unittest.skipIf("PyPy" in sys.version, "PyPy")
|
||||
@asyncio_test
|
||||
async def test_fetch_next_delete(self):
|
||||
client, server = self.client_server(auto_ismaster=True)
|
||||
client, server = self.client_server(auto_ismaster=AUTO_ISMASTER)
|
||||
|
||||
cursor = client.test.coll.find()
|
||||
self.fetch_next(cursor)
|
||||
@ -133,7 +134,7 @@ class TestAsyncIOCursor(AsyncIOMockServerTestCase):
|
||||
self.assertTrue(cursor.next_object())
|
||||
|
||||
# Not valid on server, causes CursorNotFound.
|
||||
cursor.delegate._Cursor__id = bson.int64.Int64(1234)
|
||||
cursor.delegate._id = bson.int64.Int64(1234)
|
||||
|
||||
with self.assertRaises(OperationFailure):
|
||||
await cursor.fetch_next
|
||||
@ -192,7 +193,6 @@ class TestAsyncIOCursor(AsyncIOMockServerTestCase):
|
||||
self.assertEqual(expected(100, 101), (await cursor.to_list(1)))
|
||||
self.assertEqual(expected(101, 102), (await cursor.to_list(1)))
|
||||
self.assertEqual(expected(102, 103), (await cursor.to_list(1)))
|
||||
self.assertEqual([], (await cursor.to_list(0)))
|
||||
self.assertEqual(expected(103, 105), (await cursor.to_list(2)))
|
||||
|
||||
# Only 95 docs left, make sure length=100 doesn't error or hang
|
||||
@ -309,7 +309,7 @@ class TestAsyncIOCursor(AsyncIOMockServerTestCase):
|
||||
|
||||
@asyncio_test
|
||||
async def test_cursor_explicit_close(self):
|
||||
client, server = self.client_server(auto_ismaster=True)
|
||||
client, server = self.client_server(auto_ismaster=AUTO_ISMASTER)
|
||||
collection = client.test.coll
|
||||
cursor = collection.find()
|
||||
|
||||
@ -355,7 +355,7 @@ class TestAsyncIOCursor(AsyncIOMockServerTestCase):
|
||||
|
||||
def canceled():
|
||||
try:
|
||||
self.assertFalse(cursor.delegate._Cursor__killed)
|
||||
self.assertFalse(cursor.delegate._killed)
|
||||
self.assertTrue(cursor.alive)
|
||||
|
||||
# Resume iteration
|
||||
@ -412,7 +412,7 @@ class TestAsyncIOCursor(AsyncIOMockServerTestCase):
|
||||
@unittest.skipIf("PyPy" in sys.version, "PyPy")
|
||||
@asyncio_test
|
||||
async def test_cursor_del(self):
|
||||
client, server = self.client_server(auto_ismaster=True)
|
||||
client, server = self.client_server(auto_ismaster=AUTO_ISMASTER)
|
||||
cursor = client.test.coll.find()
|
||||
|
||||
future = self.fetch_next(cursor)
|
||||
@ -586,7 +586,7 @@ class TestAsyncIOCursor(AsyncIOMockServerTestCase):
|
||||
|
||||
@asyncio_test
|
||||
async def test_generate_keys(self):
|
||||
c = self.collection
|
||||
c = self.cx
|
||||
KMS_PROVIDERS = {"local": {"key": b"\x00" * 96}}
|
||||
|
||||
async with motor_asyncio.AsyncIOMotorClientEncryption(
|
||||
|
||||
@ -127,7 +127,7 @@ class MotorGridFileTest(AsyncIOTestCase):
|
||||
|
||||
# The call tree should include PyMongo code we ran on a thread.
|
||||
formatted = "\n".join(traceback.format_tb(tb))
|
||||
self.assertTrue("_ensure_file" in formatted)
|
||||
self.assertTrue("open" in formatted)
|
||||
|
||||
@asyncio_test
|
||||
async def test_alternate_collection(self):
|
||||
|
||||
@ -893,6 +893,38 @@ class TestExamples(AsyncIOTestCase):
|
||||
print(doc)
|
||||
# End Aggregation Example 4
|
||||
|
||||
@env.require_version_min(4, 4)
|
||||
def test_aggregate_projection_example(self):
|
||||
db = self.db
|
||||
|
||||
# Start Aggregation Projection Example 1
|
||||
db.inventory.find(
|
||||
{},
|
||||
{
|
||||
"_id": 0,
|
||||
"item": 1,
|
||||
"status": {
|
||||
"$switch": {
|
||||
"branches": [
|
||||
{"case": {"$eq": ["$status", "A"]}, "then": "Available"},
|
||||
{"case": {"$eq": ["$status", "D"]}, "then": "Discontinued"},
|
||||
],
|
||||
"default": "No status found",
|
||||
}
|
||||
},
|
||||
"area": {
|
||||
"$concat": [
|
||||
{"$toString": {"$multiply": ["$size.h", "$size.w"]}},
|
||||
" ",
|
||||
"$size.uom",
|
||||
]
|
||||
},
|
||||
"reportNumber": {"$literal": 1},
|
||||
},
|
||||
)
|
||||
|
||||
# End Aggregation Projection Example 1
|
||||
|
||||
@asyncio_test
|
||||
async def test_commands(self):
|
||||
db = self.db
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
from motor.motor_asyncio import (
|
||||
AsyncIOMotorChangeStream,
|
||||
@ -9,9 +9,9 @@ from motor.motor_asyncio import (
|
||||
AsyncIOMotorDatabase,
|
||||
)
|
||||
|
||||
client: AsyncIOMotorClient[Dict[str, Any]]
|
||||
db: AsyncIOMotorDatabase[Dict[str, Any]]
|
||||
cur: AsyncIOMotorCursor[Dict[str, Any]]
|
||||
coll: AsyncIOMotorCollection[Dict[str, Any]]
|
||||
cs: AsyncIOMotorChangeStream[Dict[str, Any]]
|
||||
enc: AsyncIOMotorClientEncryption[Dict[str, Any]]
|
||||
client: AsyncIOMotorClient[dict[str, Any]]
|
||||
db: AsyncIOMotorDatabase[dict[str, Any]]
|
||||
cur: AsyncIOMotorCursor[dict[str, Any]]
|
||||
coll: AsyncIOMotorCollection[dict[str, Any]]
|
||||
cs: AsyncIOMotorChangeStream[dict[str, Any]]
|
||||
enc: AsyncIOMotorClientEncryption[dict[str, Any]]
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from typing import Iterable
|
||||
from collections.abc import Iterable
|
||||
|
||||
try:
|
||||
from mypy import api
|
||||
|
||||
@ -17,8 +17,9 @@ sample client code that uses Motor typings.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from collections.abc import Callable, Mapping
|
||||
from test.asyncio_tests import AsyncIOTestCase, asyncio_test
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Mapping, TypeVar, Union, cast
|
||||
from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
|
||||
|
||||
from bson import CodecOptions
|
||||
from bson.raw_bson import RawBSONDocument
|
||||
@ -116,11 +117,11 @@ class TestMotor(AsyncIOTestCase):
|
||||
async def test_bulk_write(self) -> None:
|
||||
await self.collection.insert_one({})
|
||||
coll = self.collection
|
||||
requests: List[InsertOne[Movie]] = [InsertOne(Movie(name="American Graffiti", year=1973))]
|
||||
requests: list[InsertOne[Movie]] = [InsertOne(Movie(name="American Graffiti", year=1973))]
|
||||
result_one = await coll.bulk_write(requests)
|
||||
self.assertTrue(result_one.acknowledged)
|
||||
new_requests: List[Union[InsertOne[Movie], ReplaceOne[Movie]]] = []
|
||||
input_list: List[Union[InsertOne[Movie], ReplaceOne[Movie]]] = [
|
||||
new_requests: list[Union[InsertOne[Movie], ReplaceOne[Movie]]] = []
|
||||
input_list: list[Union[InsertOne[Movie], ReplaceOne[Movie]]] = [
|
||||
InsertOne(Movie(name="American Graffiti", year=1973)),
|
||||
ReplaceOne({}, Movie(name="American Graffiti", year=1973)),
|
||||
]
|
||||
@ -134,14 +135,14 @@ class TestMotor(AsyncIOTestCase):
|
||||
@asyncio_test # type:ignore[misc]
|
||||
async def test_bulk_write_heterogeneous(self) -> None:
|
||||
coll = self.collection
|
||||
requests: List[Union[InsertOne[Movie], ReplaceOne, DeleteOne]] = [
|
||||
requests: list[Union[InsertOne[Movie], ReplaceOne, DeleteOne]] = [
|
||||
InsertOne(Movie(name="American Graffiti", year=1973)),
|
||||
ReplaceOne({}, {"name": "American Graffiti", "year": "WRONG_TYPE"}),
|
||||
DeleteOne({}),
|
||||
]
|
||||
result_one = await coll.bulk_write(requests)
|
||||
self.assertTrue(result_one.acknowledged)
|
||||
requests_two: List[Union[InsertOne[Movie], ReplaceOne[Movie], DeleteOne]] = [
|
||||
requests_two: list[Union[InsertOne[Movie], ReplaceOne[Movie], DeleteOne]] = [
|
||||
InsertOne(Movie(name="American Graffiti", year=1973)),
|
||||
ReplaceOne(
|
||||
{},
|
||||
@ -154,7 +155,7 @@ class TestMotor(AsyncIOTestCase):
|
||||
|
||||
@asyncio_test # type:ignore[misc]
|
||||
async def test_command(self) -> None:
|
||||
result: Dict = await self.cx.admin.command("ping")
|
||||
result: dict = await self.cx.admin.command("ping")
|
||||
result.items()
|
||||
|
||||
@asyncio_test # type:ignore[misc]
|
||||
@ -192,7 +193,7 @@ class TestMotor(AsyncIOTestCase):
|
||||
]
|
||||
)
|
||||
|
||||
class mydict(Dict[str, Any]):
|
||||
class mydict(dict[str, Any]):
|
||||
pass
|
||||
|
||||
result = coll3.aggregate(
|
||||
@ -226,7 +227,7 @@ class TestDocumentType(AsyncIOTestCase):
|
||||
|
||||
@only_type_check
|
||||
async def test_explicit_document_type(self) -> None:
|
||||
client: AsyncIOMotorClient[Dict[str, Any]] = AsyncIOMotorClient()
|
||||
client: AsyncIOMotorClient[dict[str, Any]] = AsyncIOMotorClient()
|
||||
coll = client.test.test
|
||||
retrieved = await coll.find_one({"_id": "foo"})
|
||||
assert retrieved is not None
|
||||
@ -320,7 +321,7 @@ class TestDocumentType(AsyncIOTestCase):
|
||||
|
||||
@only_type_check
|
||||
async def test_create_index(self) -> None:
|
||||
client: AsyncIOMotorClient[Dict[str, str]] = AsyncIOMotorClient("test")
|
||||
client: AsyncIOMotorClient[dict[str, str]] = AsyncIOMotorClient("test")
|
||||
db = client.test
|
||||
async with await client.start_session() as session:
|
||||
index = await db.test.create_index(
|
||||
@ -361,13 +362,13 @@ class TestCommandDocumentType(AsyncIOTestCase):
|
||||
@only_type_check
|
||||
async def test_default(self) -> None:
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
result: Dict = await client.admin.command("ping")
|
||||
result: dict = await client.admin.command("ping")
|
||||
result["a"] = 1
|
||||
|
||||
@only_type_check
|
||||
async def test_explicit_document_type(self) -> None:
|
||||
client: AsyncIOMotorClient = AsyncIOMotorClient()
|
||||
codec_options: CodecOptions[Dict[str, Any]] = CodecOptions()
|
||||
codec_options: CodecOptions[dict[str, Any]] = CodecOptions()
|
||||
result = await client.admin.command("ping", codec_options=codec_options)
|
||||
result["a"] = 1
|
||||
|
||||
|
||||
@ -100,7 +100,7 @@ class MotorTestBasic(MotorTest):
|
||||
motor_cursor = collection.find()
|
||||
cursor = motor_cursor.delegate
|
||||
|
||||
self.assertEqual(Nearest(tag_sets=[{"yay": "jesse"}]), cursor._read_preference())
|
||||
self.assertEqual(Nearest(tag_sets=[{"yay": "jesse"}]), cursor._get_read_preference())
|
||||
|
||||
cx.close()
|
||||
|
||||
|
||||
@ -20,13 +20,14 @@ import unittest
|
||||
from test import SkipTest
|
||||
from test.test_environment import db_password, db_user, env
|
||||
from test.tornado_tests import MotorMockServerTest, MotorTest, remove_all_users
|
||||
from test.utils import get_primary_pool, one
|
||||
from test.utils import AUTO_ISMASTER, get_primary_pool, one
|
||||
|
||||
import pymongo
|
||||
import pymongo.mongo_client
|
||||
from bson import CodecOptions
|
||||
from mockupdb import OpQuery
|
||||
from mockupdb import OpMsg, OpQuery
|
||||
from pymongo import CursorType, ReadPreference, WriteConcern
|
||||
from pymongo.common import MIN_SUPPORTED_WIRE_VERSION
|
||||
from pymongo.driver_info import DriverInfo
|
||||
from pymongo.errors import ConnectionFailure, OperationFailure
|
||||
from tornado import gen
|
||||
@ -191,7 +192,7 @@ class MotorClientTest(MotorTest):
|
||||
class MotorClientTimeoutTest(MotorMockServerTest):
|
||||
@gen_test
|
||||
async def test_timeout(self):
|
||||
server = self.server(auto_ismaster=True)
|
||||
server = self.server(auto_ismaster=AUTO_ISMASTER)
|
||||
client = motor.MotorClient(server.uri, socketTimeoutMS=100)
|
||||
|
||||
with self.assertRaises(pymongo.errors.AutoReconnect) as context:
|
||||
@ -205,7 +206,13 @@ class MotorClientExhaustCursorTest(MotorMockServerTest):
|
||||
def primary_server(self):
|
||||
primary = self.server()
|
||||
hosts = [primary.address_string]
|
||||
primary.autoresponds("ismaster", ismaster=True, setName="rs", hosts=hosts, maxWireVersion=6)
|
||||
primary.autoresponds(
|
||||
"ismaster",
|
||||
ismaster=True,
|
||||
setName="rs",
|
||||
hosts=hosts,
|
||||
maxWireVersion=MIN_SUPPORTED_WIRE_VERSION,
|
||||
)
|
||||
|
||||
return primary
|
||||
|
||||
@ -213,7 +220,7 @@ class MotorClientExhaustCursorTest(MotorMockServerTest):
|
||||
if rs:
|
||||
return self.primary_server()
|
||||
else:
|
||||
return self.server(auto_ismaster=True)
|
||||
return self.server(auto_ismaster=AUTO_ISMASTER)
|
||||
|
||||
async def _test_exhaust_query_server_error(self, rs):
|
||||
# When doing an exhaust query, the socket stays checked out on success
|
||||
@ -227,7 +234,8 @@ class MotorClientExhaustCursorTest(MotorMockServerTest):
|
||||
|
||||
# With Tornado, simply accessing fetch_next starts the fetch.
|
||||
fetch_next = cursor.fetch_next
|
||||
request = await self.run_thread(server.receives, OpQuery)
|
||||
expected = OpQuery if pymongo.version_tuple[0:2] < (4, 14) else OpMsg({})
|
||||
request = await self.run_thread(server.receives, expected)
|
||||
request.fail(code=1)
|
||||
|
||||
with self.assertRaises(pymongo.errors.OperationFailure):
|
||||
@ -238,10 +246,12 @@ class MotorClientExhaustCursorTest(MotorMockServerTest):
|
||||
|
||||
@gen_test
|
||||
async def test_exhaust_query_server_error_standalone(self):
|
||||
raise self.skipTest("MOTOR-1472")
|
||||
await self._test_exhaust_query_server_error(rs=False)
|
||||
|
||||
@gen_test
|
||||
async def test_exhaust_query_server_error_rs(self):
|
||||
raise self.skipTest("MOTOR-1472")
|
||||
await self._test_exhaust_query_server_error(rs=True)
|
||||
|
||||
async def _test_exhaust_query_network_error(self, rs):
|
||||
@ -260,7 +270,8 @@ class MotorClientExhaustCursorTest(MotorMockServerTest):
|
||||
|
||||
# With Tornado, simply accessing fetch_next starts the fetch.
|
||||
fetch_next = cursor.fetch_next
|
||||
request = await self.run_thread(server.receives, OpQuery)
|
||||
expected = OpQuery if pymongo.version_tuple[0:2] < (4, 14) else OpMsg({})
|
||||
request = await self.run_thread(server.receives, expected)
|
||||
request.hangs_up()
|
||||
|
||||
with self.assertRaises(pymongo.errors.ConnectionFailure):
|
||||
@ -290,7 +301,7 @@ class MotorClientHandshakeTest(MotorMockServerTest):
|
||||
future = client.db.command("ping")
|
||||
ismaster = await self.run_thread(server.receives, "ismaster")
|
||||
meta = ismaster.doc["client"]
|
||||
self.assertEqual("PyMongo|Motor", meta["driver"]["name"])
|
||||
self.assertIn("|Motor", meta["driver"]["name"])
|
||||
self.assertIn("Tornado", meta["platform"])
|
||||
self.assertTrue(
|
||||
meta["driver"]["version"].endswith(motor.version),
|
||||
@ -316,7 +327,7 @@ class MotorClientHandshakeTest(MotorMockServerTest):
|
||||
future = client.db.command("ping")
|
||||
handshake = await self.run_thread(server.receives, "ismaster")
|
||||
meta = handshake.doc["client"]
|
||||
self.assertEqual(f"PyMongo|Motor|{driver_info.name}", meta["driver"]["name"])
|
||||
self.assertIn(f"|Motor|{driver_info.name}", meta["driver"]["name"])
|
||||
self.assertIn("Tornado", meta["platform"])
|
||||
self.assertIn(f"|{driver_info.platform}", meta["platform"])
|
||||
self.assertTrue(
|
||||
|
||||
@ -272,7 +272,7 @@ class MotorCollectionTest(MotorTest):
|
||||
@gen_test
|
||||
async def test_async_create_encrypted_collection(self):
|
||||
await self.db.drop_collection("test_collection")
|
||||
c = self.collection
|
||||
c = self.cx
|
||||
KMS_PROVIDERS = {"local": {"key": b"\x00" * 96}}
|
||||
self.cx.drop_database("db")
|
||||
async with motor.MotorClientEncryption(
|
||||
@ -289,9 +289,10 @@ class MotorCollectionTest(MotorTest):
|
||||
self.assertEqual(exc.exception.code, 121)
|
||||
await self.db.drop_collection("testing1", encrypted_fields=ef)
|
||||
|
||||
@env.require_version_min(8, 0, -1, -1)
|
||||
@gen_test
|
||||
async def test_async_encrypt_expression(self):
|
||||
c = self.collection
|
||||
c = self.cx
|
||||
KMS_PROVIDERS = {"local": {"key": b"\x00" * 96}}
|
||||
self.cx.drop_database("db")
|
||||
async with motor.MotorClientEncryption(
|
||||
@ -301,12 +302,12 @@ class MotorCollectionTest(MotorTest):
|
||||
"local", key_alt_names=["pymongo_encryption_example_1"]
|
||||
)
|
||||
name = "DoubleNoPrecision"
|
||||
range_opts = RangeOpts(sparsity=1)
|
||||
range_opts = RangeOpts(sparsity=1, trim_factor=1)
|
||||
for i in [6.0, 30.0, 200.0]:
|
||||
insert_payload = await client_encryption.encrypt(
|
||||
float(i),
|
||||
key_id=data_key,
|
||||
algorithm=Algorithm.RANGEPREVIEW,
|
||||
algorithm=Algorithm.RANGE,
|
||||
contention_factor=0,
|
||||
range_opts=range_opts,
|
||||
)
|
||||
@ -325,8 +326,8 @@ class MotorCollectionTest(MotorTest):
|
||||
]
|
||||
},
|
||||
key_id=data_key,
|
||||
algorithm=Algorithm.RANGEPREVIEW,
|
||||
query_type=QueryType.RANGEPREVIEW,
|
||||
algorithm=Algorithm.RANGE,
|
||||
query_type=QueryType.RANGE,
|
||||
contention_factor=0,
|
||||
range_opts=range_opts,
|
||||
)
|
||||
@ -335,7 +336,7 @@ class MotorCollectionTest(MotorTest):
|
||||
await self.collection.explicit_encryption.find(find_payload).to_list(3),
|
||||
key=lambda x: x["_id"],
|
||||
)
|
||||
for elem, expected in zip(sorted_find, [6.0, 30.0, 200.0]):
|
||||
for elem, expected in zip(sorted_find, [6.0, 30.0, 200.0], strict=False):
|
||||
self.assertEqual(elem[f"encrypted{name}"], expected)
|
||||
|
||||
|
||||
|
||||
@ -31,17 +31,19 @@ motor_only = set(["delegate", "get_io_loop", "io_loop", "wrap"])
|
||||
|
||||
pymongo_only = set(["next"])
|
||||
|
||||
pymongo_gridfs_only = set(["delete_by_name", "rename_by_name"])
|
||||
|
||||
motor_client_only = motor_only.union(["open"])
|
||||
|
||||
pymongo_client_only = set([]).union(pymongo_only)
|
||||
pymongo_client_only = set(["eq_props", "append_metadata"]).union(pymongo_only)
|
||||
|
||||
pymongo_database_only = set([]).union(pymongo_only)
|
||||
|
||||
pymongo_collection_only = set([]).union(pymongo_only)
|
||||
|
||||
motor_cursor_only = set(
|
||||
["fetch_next", "to_list", "each", "started", "next_object", "closed"]
|
||||
).union(motor_only)
|
||||
motor_cursor_only = set(["fetch_next", "each", "started", "next_object", "closed"]).union(
|
||||
motor_only
|
||||
)
|
||||
|
||||
pymongo_cursor_only = set(["retrieved"])
|
||||
|
||||
@ -113,12 +115,12 @@ class MotorCoreTestGridFS(MotorTest):
|
||||
motor_gridfs_only = set(["collection"]).union(motor_only)
|
||||
|
||||
self.assertEqual(
|
||||
attrs(GridFSBucket(env.sync_cx.test)),
|
||||
attrs(GridFSBucket(env.sync_cx.test)) - pymongo_gridfs_only,
|
||||
attrs(MotorGridFSBucket(self.cx.test)) - motor_gridfs_only,
|
||||
)
|
||||
|
||||
def test_gridin_attrs(self):
|
||||
motor_gridin_only = set(["set"]).union(motor_only)
|
||||
motor_gridin_only = set([]).union(motor_only)
|
||||
gridin_only = set(["md5"])
|
||||
|
||||
self.assertEqual(
|
||||
@ -137,6 +139,7 @@ class MotorCoreTestGridFS(MotorTest):
|
||||
"truncate",
|
||||
"flush",
|
||||
"fileno",
|
||||
"open",
|
||||
"closed",
|
||||
"writelines",
|
||||
"isatty",
|
||||
|
||||
@ -27,6 +27,7 @@ from test.tornado_tests import (
|
||||
server_is_mongos,
|
||||
)
|
||||
from test.utils import (
|
||||
AUTO_ISMASTER,
|
||||
TestListener,
|
||||
get_async_test_timeout,
|
||||
get_primary_pool,
|
||||
@ -90,7 +91,7 @@ class MotorCursorTest(MotorMockServerTest):
|
||||
if "PyPy" in sys.version:
|
||||
raise SkipTest("PyPy")
|
||||
|
||||
client, server = self.client_server(auto_ismaster=True)
|
||||
client, server = self.client_server(auto_ismaster=AUTO_ISMASTER)
|
||||
cursor = client.test.coll.find()
|
||||
|
||||
# With Tornado, simply accessing fetch_next starts the fetch.
|
||||
@ -138,7 +139,7 @@ class MotorCursorTest(MotorMockServerTest):
|
||||
self.assertTrue(cursor.next_object())
|
||||
|
||||
# Not valid on server, causes CursorNotFound.
|
||||
cursor.delegate._Cursor__id = bson.int64.Int64(1234)
|
||||
cursor.delegate._id = bson.int64.Int64(1234)
|
||||
|
||||
with self.assertRaises(OperationFailure):
|
||||
await cursor.fetch_next
|
||||
@ -266,7 +267,7 @@ class MotorCursorTest(MotorMockServerTest):
|
||||
|
||||
@gen_test
|
||||
async def test_cursor_explicit_close(self):
|
||||
client, server = self.client_server(auto_ismaster=True)
|
||||
client, server = self.client_server(auto_ismaster=AUTO_ISMASTER)
|
||||
collection = client.test.coll
|
||||
cursor = collection.find()
|
||||
|
||||
@ -309,7 +310,7 @@ class MotorCursorTest(MotorMockServerTest):
|
||||
|
||||
def canceled():
|
||||
try:
|
||||
self.assertFalse(cursor.delegate._Cursor__killed)
|
||||
self.assertFalse(cursor.delegate._killed)
|
||||
self.assertTrue(cursor.alive)
|
||||
|
||||
# Resume iteration
|
||||
@ -368,7 +369,7 @@ class MotorCursorTest(MotorMockServerTest):
|
||||
if "PyPy" in sys.version:
|
||||
raise SkipTest("PyPy")
|
||||
|
||||
client, server = self.client_server(auto_ismaster=True)
|
||||
client, server = self.client_server(auto_ismaster=AUTO_ISMASTER)
|
||||
cursor = client.test.coll.find()
|
||||
|
||||
future = cursor.fetch_next
|
||||
@ -518,7 +519,7 @@ class MotorCursorTest(MotorMockServerTest):
|
||||
|
||||
@gen_test
|
||||
async def test_generate_keys(self):
|
||||
c = self.collection
|
||||
c = self.cx
|
||||
KMS_PROVIDERS = {"local": {"key": b"\x00" * 96}}
|
||||
|
||||
async with motor.MotorClientEncryption(
|
||||
|
||||
@ -126,7 +126,7 @@ class MotorGridFileTest(MotorTest):
|
||||
|
||||
# The call tree should include PyMongo code we ran on a thread.
|
||||
formatted = "\n".join(traceback.format_tb(tb))
|
||||
self.assertTrue("_ensure_file" in formatted)
|
||||
self.assertTrue("open" in formatted)
|
||||
|
||||
@gen_test
|
||||
async def test_alternate_collection(self):
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from bson import SON
|
||||
from pymongo import monitoring
|
||||
from pymongo import common, monitoring
|
||||
|
||||
"""Utilities for testing Motor with any framework."""
|
||||
|
||||
@ -28,6 +28,9 @@ import warnings
|
||||
# mypy: ignore-errors
|
||||
|
||||
|
||||
AUTO_ISMASTER = {"maxWireVersion": common.MIN_SUPPORTED_WIRE_VERSION}
|
||||
|
||||
|
||||
def one(s):
|
||||
"""Get one element of a set"""
|
||||
return next(iter(s))
|
||||
|
||||
45
tox.ini
45
tox.ini
@ -18,6 +18,11 @@ envlist =
|
||||
linkcheck,
|
||||
# Test with the latest PyMongo.
|
||||
test-pymongo-latest,
|
||||
# Test with oldest supported PyMongo.
|
||||
test-pymongo-4.9,
|
||||
# Test with other supported stable PyMongos.
|
||||
test-pymongo-4.10,
|
||||
test-pymongo-4.11,
|
||||
# Apply PyMongo's test suite to Motor via Synchro.
|
||||
synchro
|
||||
# Run synchro tests with enterprise auth
|
||||
@ -38,6 +43,9 @@ labels = # Use labels and -m instead of -e so that tox -m <label> fails instantl
|
||||
doctest = doctest
|
||||
checklink = checklink
|
||||
test-pymongo-latest = test-pymongo-latest
|
||||
test-pymongo-4.9 = test-pymongo-4.9
|
||||
test-pymongo-4.10 = test-pymongo-4.10
|
||||
test-pymongo-4.11 = test-pymongo-4.11
|
||||
synchro = synchro
|
||||
enterprise-synchro = enterprise-synchro
|
||||
lint = lint
|
||||
@ -78,7 +86,7 @@ deps =
|
||||
-rrequirements/docs.txt
|
||||
changedir = doc
|
||||
commands =
|
||||
python -m sphinx -q -E -W -b html . {envtmpdir}/html {posargs}
|
||||
python -m sphinx -q -W -E -b html . {envtmpdir}/html {posargs}
|
||||
|
||||
[testenv:doctest]
|
||||
setenv = PYTHONHASHSEED=0
|
||||
@ -101,11 +109,34 @@ extras =
|
||||
encryption
|
||||
test
|
||||
commands =
|
||||
# TODO: Use "master" as part of MOTOR-1330
|
||||
pip install git+https://github.com/mongodb/mongo-python-driver.git@v4.8
|
||||
pip install https://github.com/mongodb/mongo-python-driver/archive/master.tar.gz
|
||||
pip install -q --pre --prefer-binary pymongocrypt
|
||||
python --version
|
||||
python -c "import pymongo; print('PyMongo %s' % (pymongo.version,))"
|
||||
python -m pytest -s -v {posargs}
|
||||
|
||||
[testenv:test-pymongo-4.9]
|
||||
extras =
|
||||
encryption
|
||||
test
|
||||
commands =
|
||||
pip install pymongo==4.9
|
||||
python -m pytest -v {posargs}
|
||||
|
||||
[testenv:test-pymongo-4.10]
|
||||
extras =
|
||||
encryption
|
||||
test
|
||||
commands =
|
||||
pip install pymongo==4.10
|
||||
python -m pytest -v {posargs}
|
||||
|
||||
[testenv:test-pymongo-4.11]
|
||||
extras =
|
||||
encryption
|
||||
test
|
||||
commands =
|
||||
pip install pymongo==4.11
|
||||
python -m pytest -v {posargs}
|
||||
|
||||
[testenv:synchro]
|
||||
@ -116,8 +147,7 @@ allowlist_externals =
|
||||
setenv =
|
||||
PYTHONPATH = {envtmpdir}/mongo-python-driver
|
||||
commands =
|
||||
# TODO: Use "master" as part of MOTOR-1330
|
||||
git clone --depth 1 --branch v4.8 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 {envtmpdir}/mongo-python-driver
|
||||
python -m pip install -e {envtmpdir}/mongo-python-driver
|
||||
python -m synchro.synchrotest {envtmpdir}/mongo-python-driver -v {posargs}
|
||||
|
||||
@ -132,10 +162,9 @@ passenv =
|
||||
setenv =
|
||||
PYTHONPATH = {envtmpdir}/mongo-python-driver
|
||||
commands =
|
||||
# TODO: Use "master" as part of MOTOR-1330
|
||||
git clone --depth 1 --branch v4.8 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 {envtmpdir}/mongo-python-driver
|
||||
python -m pip install -e {envtmpdir}/mongo-python-driver
|
||||
python -m synchro.synchrotest {envtmpdir}/mongo-python-driver -v test/test_auth.py
|
||||
python -m synchro.synchrotest {envtmpdir}/mongo-python-driver -m auth -v test/test_auth.py
|
||||
|
||||
[testenv:lint]
|
||||
deps =
|
||||
|
||||
Loading…
Reference in New Issue
Block a user