Compare commits

...

35 Commits

Author SHA1 Message Date
dependabot[bot]
3cd98d9b94
Update pytest requirement from >=7 to >=9.0.3 (#382)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-27 19:44:47 -04:00
dependabot[bot]
4fe13c6f25
Bump the actions group with 3 updates (#375)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-04 15:45:08 -08:00
dependabot[bot]
f45226d02f
Bump github/codeql-action from 4.32.2 to 4.32.3 in the actions group (#373)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-17 07:45:36 -06:00
dependabot[bot]
c869e5cd7d
Bump github/codeql-action from 4.32.0 to 4.32.2 in the actions group (#372)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-09 06:25:45 -06:00
dependabot[bot]
160dbce99f
Bump the actions group with 2 updates (#371)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 06:28:13 -06:00
Steven Silvester
2433f62fd9
PYTHON-5711 Add zizmor config (#370) 2026-01-30 14:58:55 -06:00
Pablo Castellano
99b56b4633
Fix link in README.md (#369) 2026-01-28 15:06:14 -06:00
dependabot[bot]
bb744b7b5c
Bump the actions group with 2 updates (#368)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-26 07:56:53 -06:00
dependabot[bot]
94a26fa9da
Bump the actions group across 1 directory with 2 updates (#367)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-20 12:12:43 -06:00
dependabot[bot]
b3b102a89d
Bump zizmorcore/zizmor-action from cb3d8e846e148d1111d90b03375b9c03deceda37 to 706c51b5bce7adb027de71ab36d865f5d3fcc7b7 in the actions group (#365)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 09:16:34 -06:00
dependabot[bot]
9bae93d875
Bump furo from 2025.9.25 to 2025.12.19 (#364)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 07:40:00 -06:00
dependabot[bot]
aab94545dd
Bump github/codeql-action from 4.31.8 to 4.31.9 in the actions group (#363)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 07:39:36 -06:00
dependabot[bot]
ccc861c5c7
Bump the actions group with 4 updates (#362)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 06:33:08 -06:00
dependabot[bot]
87d1c9ed87
Bump github/codeql-action from 4.31.6 to 4.31.7 in the actions group (#361)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 05:31:38 -06:00
dependabot[bot]
77bd8ba755
Bump the actions group with 2 updates (#360)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:24:25 -06:00
dependabot[bot]
61c0e5ccf0
Bump the actions group with 4 updates (#359)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 05:54:44 -06:00
dependabot[bot]
156f3b5f16
Bump zizmorcore/zizmor-action from da5ac40c5419dcf7f21630fb2f95e725ae8fb9d5 to 1aba86d8e1245be7a9ca003d46fcc85a76e6aa61 in the actions group (#358)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-11 09:24:02 -06:00
dependabot[bot]
bafa539ed0
Bump github/codeql-action from 4.31.0 to 4.31.2 in the actions group (#357)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 08:22:02 -06:00
Steven Silvester
d0ed67cd80
MOTOR-1478 Update feedback link (#356) 2025-10-29 07:57:51 -05:00
dependabot[bot]
7785176fdc
Bump the actions group with 3 updates (#355)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 07:45:42 -05:00
dependabot[bot]
536b2dd9d8
Bump github/codeql-action from 3.30.6 to 4.30.8 in the actions group (#354)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Steven Silvester <steve.silvester@mongodb.com>
2025-10-20 09:43:22 -05:00
Steven Silvester
224da029d5
MOTOR-1477 Add workaround for missing compression.zstd (#353) 2025-10-07 12:28:47 -05:00
Steven Silvester
52234081fb
MOTOR-1476 Fix linkcheck for JIRA release notes (#352) 2025-10-07 12:27:48 -05:00
dependabot[bot]
b81fd4e181
Bump the actions group with 2 updates (#351)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 16:50:30 -05:00
dependabot[bot]
820ba59552
Update sphinx requirement from <8,>=5.3 to >=5.3,<9 (#348)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Steven Silvester <steven.silvester@ieee.org>
Co-authored-by: Steven Silvester <steve.silvester@mongodb.com>
2025-09-30 10:26:01 -05:00
dependabot[bot]
144c460d8e
Bump furo from 2024.8.6 to 2025.9.25 (#349)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-30 06:29:33 -05:00
dependabot[bot]
d6c688b609
Update sphinx-rtd-theme requirement from <3,>=2 to >=2,<4 (#347)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-30 06:20:09 -05:00
dependabot[bot]
79fd03a68f
Bump the actions group with 7 updates (#350)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Steven Silvester <steve.silvester@mongodb.com>
2025-09-30 06:19:20 -05:00
Steven Silvester
33e4f112c7
MOTOR-1475 Update docs references (#346) 2025-09-15 15:54:53 -05:00
Steven Silvester
12d9d7db05
MOTOR-1474 Update evergreen tests to use RHEL8 (#345) 2025-08-15 13:19:58 -05:00
Noah Stapp
5bcdd4ad6a
MOTOR-1470 - Add Deprecation Warning to Motor (#340) 2025-08-04 14:35:30 -04:00
Steven Silvester
5fc7c41fb5
MOTOR-1473 Add support for Python 3.14 and drop 3.9 support (#344) 2025-07-30 14:55:53 -05:00
Jib
bbada7dace
PYTHON-5438: Create CODEOWNERS for motor (#342)
bypassing docs failures
2025-07-21 13:58:33 -04:00
Steven Silvester
4bb5e32e80
MOTOR-1471 Remove tests for MongoDB 4.0 (#343) 2025-07-15 09:00:32 -05:00
Steven Silvester
8412d20e28
PYTHON-5430 Use the zizmor action (#341) 2025-07-11 16:46:46 -05:00
39 changed files with 281 additions and 260 deletions

View File

@ -346,33 +346,6 @@ tasks:
# Test tasks {{{
- 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:
@ -636,14 +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-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"
@ -660,55 +629,55 @@ axes:
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.9/bin/python3"
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.9/bin/python3"
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.9/bin/python3"
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
- id: "test-pymongo-latest"
variables:
TOX_ENV: "test-pymongo-latest"
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
- id: "synchro-py39"
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
- id: "synchro-py310"
variables:
TOX_ENV: "synchro"
PYTHON_BINARY: "/opt/python/3.9/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.9 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.9/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-py39"
variables:
TOX_ENV: "test"
PYTHON_BINARY: "c:/python/Python39/python.exe"
- id: "test-py310"
variables:
TOX_ENV: "test"
@ -721,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"
@ -728,9 +705,6 @@ 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"
@ -751,7 +725,7 @@ buildvariants:
# TODO: synchro needs PyMongo's updated SSL test certs,
# which may require Motor test suite changes.
- os: "*"
tox-env: ["synchro-py39", "synchro-py312"]
tox-env: ["synchro-py310", "synchro-py313"]
ssl: "ssl"
tasks:
- ".rapid"
@ -764,11 +738,11 @@ buildvariants:
- ".4.2"
- ".4.0"
- 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"
@ -811,7 +785,7 @@ buildvariants:
- matrix_name: "enterprise-auth"
display_name: "Enterprise Auth-${tox-env}"
matrix_spec: {"tox-env": ["synchro-py39", "synchro-py312"], ssl: "ssl"}
matrix_spec: {"tox-env": ["synchro-py310", "synchro-py313"], ssl: "ssl"}
run_on:
- "rhel84-small"
tasks:
@ -823,7 +797,7 @@ buildvariants:
- "rhel84-small"
expansions:
TOX_ENV: "docs"
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
tasks:
- name: "docs"
@ -833,6 +807,6 @@ buildvariants:
- "rhel84-small"
expansions:
TOX_ENV: "doctest"
PYTHON_BINARY: "/opt/python/3.9/bin/python3"
PYTHON_BINARY: "/opt/python/3.10/bin/python3"
tasks:
- name: "doctest"

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
* @mongodb/dbx-python

View File

@ -44,18 +44,18 @@ jobs:
- 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@28deaeda66b76a05916b6923827895f2b14ab387 # v3
uses: github/codeql-action/init@c793b717bc78562f491db7b0e93a3a178b099162 # v4
with:
languages: ${{ matrix.language }}
build-mode: none
@ -71,6 +71,6 @@ jobs:
pip install -e .
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3
uses: github/codeql-action/analyze@c793b717bc78562f491db7b0e93a3a178b099162 # v4
with:
category: "/language:${{matrix.language}}"

View File

@ -24,12 +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
@ -37,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/*"

View File

@ -38,17 +38,16 @@ 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:
dry_run: ${{ env.DRY_RUN }}
@ -74,19 +73,19 @@ jobs:
id-token: write
steps:
- name: Download all the dists
uses: actions/download-artifact@v4
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@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1
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@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
post-publish:
needs: [publish]
@ -98,17 +97,16 @@ jobs:
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/post-publish@v2
- uses: mongodb-labs/drivers-github-tools/python/post-publish@v3
with:
following_version: ${{ env.FOLLOWING_VERSION }}
product_name: ${{ env.PRODUCT_NAME }}

View File

@ -20,15 +20,15 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
python-version: ["3.9", "3.12", "3.13"]
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'
@ -49,12 +49,12 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: 3.9
python-version: '3.10'
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install Python dependencies
@ -67,12 +67,12 @@ jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: 3.9
python-version: '3.10'
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install Python dependencies
@ -83,7 +83,7 @@ jobs:
- name: Run linkcheck
run: tox -m linkcheck
- name: Start MongoDB
uses: supercharge/mongodb-github-action@90004df786821b6308fb02299e5835d0dae05d0d # 1.12.0
uses: supercharge/mongodb-github-action@315db7fe45ac2880b7758f1933e6e5d59afd5e94 # 1.12.1
with:
mongodb-version: 5.0
- name: Run doctest
@ -92,12 +92,12 @@ jobs:
release:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: 3.9
python-version: '3.10'
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install Python dependencies
@ -111,11 +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'

View File

@ -1,4 +1,4 @@
name: GitHub Actions Security Analysis with zizmor
name: GitHub Actions Security Analysis with zizmor 🌈
on:
push:
@ -14,19 +14,8 @@ jobs:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@9d7e65c320fdb52dcd45ffaa68deb6c02c8754d9 # v1
- name: Get zizmor
run: cargo install zizmor
- name: Run zizmor
run: zizmor --format sarif . > results.sarif
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3
with:
sarif_file: results.sarif
category: zizmor
- name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d

7
.github/zizmor.yml vendored Normal file
View 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

View File

@ -35,7 +35,7 @@ Python version on your path, and run:
tox -m test
```
The doctests pass with Python 3.9+ 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

View File

@ -12,7 +12,7 @@
> 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/>.
> For help transitioning, see the Migrate to PyMongo Async guide: https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/.
## About
@ -116,7 +116,7 @@ by asyncio. It requires:
- Unix (including macOS) or Windows.
- [PyMongo](http://pypi.python.org/pypi/pymongo/) >=4.9,<5
- Python 3.9+
- Python 3.10+
Optional dependencies:
@ -192,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.9+. 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`.

View File

@ -3,6 +3,18 @@ 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
-----------
@ -229,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.
@ -697,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.
@ -729,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. ``{}``).
@ -850,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:

View File

@ -73,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"
@ -221,8 +228,6 @@ 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),

View File

@ -49,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
@ -59,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)

View File

@ -74,7 +74,7 @@ Typed Client
:class:`~motor.motor_asyncio.AsyncIOMotorClient` is generic on the document type used to decode BSON documents.
You can specify a :class:`~bson.raw_bson.RawBSONDocument` document type:
You can specify a :class:`~pymongo.raw_bson.RawBSONDocument` document type:
.. code-block:: python
@ -89,7 +89,7 @@ You can specify a :class:`~bson.raw_bson.RawBSONDocument` document type:
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:`~bson.son.SON`:
Subclasses of :py:class:`collections.abc.Mapping` can also be used, such as :class:`~pymongo.son.SON`:
.. code-block:: python
@ -105,7 +105,7 @@ Subclasses of :py:class:`collections.abc.Mapping` can also be used, such as :cla
assert result is not None
assert result["x"] == 1
Note that when using :class:`~bson.son.SON`, the key and value types must be given, e.g. ``SON[str, Any]``.
Note that when using :class:`~pymongo.son.SON`, the key and value types must be given, e.g. ``SON[str, Any]``.
Typed Collection
@ -260,7 +260,7 @@ match a well-defined schema using :py:class:`~typing.TypedDict`.
Typed Command
-------------
When using the :meth:`~motor.motor_asyncio.AsyncIOMotorDatabase.command`, you can specify the document type by providing a custom :class:`~bson.codec_options.CodecOptions`:
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
@ -280,7 +280,7 @@ For :py:class:`~typing.TypedDict`, use the form: ``options: CodecOptions[MyTyped
Typed BSON Decoding
-------------------
You can specify the document type returned by :mod:`bson` decoding functions by providing :class:`~bson.codec_options.CodecOptions`:
You can specify the document type returned by :mod:`bson` decoding functions by providing :class:`~pymongo.codec_options.CodecOptions`:
.. code-block:: python
@ -302,7 +302,7 @@ You can specify the document type returned by :mod:`bson` decoding functions by
rt_document = decode(bsonbytes, codec_options=options)
assert rt_document.foo() == "bar"
:class:`~bson.raw_bson.RawBSONDocument` and :py:class:`~typing.TypedDict` are also supported.
: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(...)``.
@ -363,7 +363,7 @@ Other times ``mypy`` will catch an actual error, like the following code:
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:`~bson.raw_bson.RawBSONDocument`, which is read-only.:
Another example is trying to set a value on a :class:`~pymongo.raw_bson.RawBSONDocument`, which is read-only.:
.. code-block:: python

View File

@ -60,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

View File

@ -27,7 +27,7 @@ asyncio. It requires:
* Unix (including macOS) or Windows.
* PyMongo_ >=4.9,<5
* Python 3.9+
* Python 3.10+
Optional dependencies:
@ -41,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]"

View File

@ -186,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.
@ -416,8 +416,8 @@ 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.
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/
@ -454,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

View File

@ -10,7 +10,7 @@ Requirements
The current version of Motor requires:
* CPython 3.9 and later.
* CPython 3.10 and later.
* PyMongo_ 4.9 and later.
Motor can integrate with either Tornado or asyncio.
@ -125,47 +125,51 @@ Motor 3.5 dropped support for Python 3.7 and added support for Python 3.13.
Motor 3.7 dropped support for Python 3.8.
+---------------------------------------------------------------------+
| Python Version |
+=====================+=====+=====+=====+=====+=====+=====+=====+=====+
| | 3.6 | 3.7 | 3.8 | 3.9 | 3.10| 3.11| 3.12| 3.13|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| Motor Version | 1.0 | Y |**N**|**N**|**N**|**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 1.1 | Y |**N**|**N**|**N**|**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 1.2 | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 1.3 | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 2.0 | Y | Y |**N**|**N**|**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 2.1 | Y | Y | Y |**N**|**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 2.2 | Y | Y | Y |**N**|**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 2.3 | Y | Y | Y |**N**|**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 2.4 | Y | Y | Y | Y |**N**|**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 2.5 | Y | Y | Y | Y | Y |**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 3.0 |**N**| Y | Y | Y | Y |**N**|**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 3.1 |**N**| Y | Y | Y | Y | Y |**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 3.2 |**N**| Y | Y | Y | Y | Y |**N**|**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 3.3 |**N**| Y | Y | Y | Y | Y | Y |**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 3.4 |**N**| Y | Y | Y | Y | Y | Y |**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 3.5 |**N**|**N**| Y | Y | Y | Y | Y |**N**|
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 3.6 |**N**|**N**| Y | Y | Y | Y | Y | Y |
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| | 3.7 |**N**|**N**|**N**| Y | Y | Y | Y | Y |
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
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
-------------

View File

@ -14,16 +14,16 @@
"""Version-related data for motor."""
import re
from typing import List, Tuple, Union
from typing import Union
__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):

View File

@ -171,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:
@ -227,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`.
@ -693,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`.
@ -771,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
@ -782,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`.

View File

@ -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,

View File

@ -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
@ -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.

View File

@ -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

View File

@ -1,4 +1,5 @@
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

View File

@ -73,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
@ -255,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

View 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

View File

@ -1,4 +1,5 @@
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

View File

@ -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.9"
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.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.9"
python_version = "3.10"
strict = true
pretty = true
show_error_context = true
@ -103,10 +103,11 @@ filterwarnings = [
# 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]

View File

@ -1,6 +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==2024.8.6
furo==2025.12.19

View File

@ -1,7 +1,7 @@
pytest>=7
pytest>=9.0.3
mockupdb
tornado>=5
aiohttp>=3.8.7
motor[encryption]
cffi>=1.17.0rc1;python_version=="3.13"
cffi>=1.17.0rc1;python_version>="3.13"
pytest_asyncio

View File

@ -299,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

View File

@ -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

View File

@ -334,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)

View File

@ -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]]

View File

@ -1,7 +1,7 @@
import os
import sys
import unittest
from typing import Iterable
from collections.abc import Iterable
try:
from mypy import api

View File

@ -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

View File

@ -25,7 +25,7 @@ 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
@ -234,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):
@ -245,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):
@ -267,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):

View File

@ -336,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)

View File

@ -35,7 +35,7 @@ pymongo_gridfs_only = set(["delete_by_name", "rename_by_name"])
motor_client_only = motor_only.union(["open"])
pymongo_client_only = set(["eq_props"]).union(pymongo_only)
pymongo_client_only = set(["eq_props", "append_metadata"]).union(pymongo_only)
pymongo_database_only = set([]).union(pymongo_only)