PyMongo has a large community and contributions are always encouraged. Contributions can be as simple as minor tweaks to the documentation. Please read these guidelines before sending a pull request.
Before starting to write code, look for existing tickets or create one for your specific issue or feature request. That way you avoid working on something that might not be of interest or that has already been addressed.
PyMongo supports CPython 3.9+ and PyPy3.10+. Language features not supported by all interpreters can not be used.
PyMongo follows PEP8 including 4 space indents and 79 character line limits.
- Avoid backward breaking changes if at all possible.
- Write inline documentation for new classes and methods.
- We use uv for python environment management and packaging.
- We use just as our task runner.
- Write tests and make sure they pass (make sure you have a mongod
running on the default port, then execute
just testfrom the cmd line to run the test suite). - Add yourself to doc/contributors.rst
:)
Our Pull Request Policy is based on this Code Review Developer Guide
The expectation for any code author is to provide all the context needed in the space of a pull request for any engineer to feel equipped to review the code. Depending on the type of change, do your best to highlight important new functions or objects you've introduced in the code; think complex functions or new abstractions. Whilst it may seem like more work for you to adjust your pull request, the reality is your likelihood for getting review sooner shoots up.
Self Review Guidelines to follow
-
If the PR is too large, split it if possible.
-
Use 250 LoC (excluding test data and config changes) as a rule-of-thumb.
-
Moving and changing code should be in separate PRs or commits.
- Moving: Taking large code blobs and transplanting them to another file. There's generally no (or very little) actual code changed other than a cut and paste. It can even be extended to large deletions.
- Changing: Adding code changes (be that refactors or functionality additions/subtractions).
- These two, when mixed, can muddy understanding and sometimes make it harder for reviewers to keep track of things.
-
-
Prefer explaining with code comments instead of PR comments.
Provide background
- The PR description and linked tickets should answer the "what" and "why" of the change. The code change explains the "how".
Follow the Template
-
Please do not deviate from the template we make; it is there for a lot of reasons. If it is a one line fix, we still need to have context on what and why it is needed.
-
If making a versioning change, please let that be known. See examples below:
versionadded:: 3.11versionchanged:: 3.5
Pull Request Template Breakdown
-
Github PR Title
- The PR Title format should always be
[JIRA-ID] : Jira Title or Blurb Summary.
- The PR Title format should always be
-
JIRA LINK
-
Convenient link to the associated JIRA ticket.
-
Summary
- Small blurb on why this is needed. The JIRA task should have the more in-depth description, but this should still, at a high level, give anyone looking an understanding of why the PR has been checked in.
-
Changes in this PR
- The explicit code changes that this PR is introducing. This should be more specific than just the task name. (Unless the task name is very clear).
-
Test Plan
- Everything needs a test description. Describe what you did to validate your changes actually worked; if you did nothing, then document you did not test it. Aim to make these steps reproducible by other engineers, specifically with your primary reviewer in mind.
-
Screenshots
- Any images that provide more context to the PR. Usually, these just coincide with the test plan.
-
Callouts or follow-up items
- This is a good place for identifying "to-dos" that you've placed in the code (Must have an accompanying JIRA Ticket).
- Potential bugs that you are unsure how to test in the code.
- Opinions you want to receive about your code.
PyMongo uses pre-commit for
managing linting of the codebase. pre-commit performs various checks
on all files in PyMongo and uses tools that help follow a consistent
code style within the codebase.
To set up pre-commit locally, run:
brew install pre-commit
pre-commit installTo run pre-commit manually, run:
pre-commit run --all-filesTo run a manual hook like ruff manually, run:
pre-commit run --all-files --hook-stage manual ruffTypically we use just to run the linters, e.g.
just install # this will install a venv with pre-commit installed, and install the pre-commit hook.
just typing-mypy
just run lint-manualTo contribute to the API documentation just make your changes to the inline documentation of the appropriate source code or rst file in a branch and submit a pull request. You might also use the GitHub Edit button.
We use reStructuredText for all documentation including narrative docs, and the Sphinx docstring format.
You can build the documentation locally by running:
just docsWhen updating docs, it can be helpful to run the live docs server as:
just docs-serveBrowse to the link provided, and then as you make changes to docstrings or narrative docs, the pages will re-render and the browser will automatically refresh.
- Run
just installto set a local virtual environment, or you can manually create a virtual environment and runpytestdirectly. If you want to use a specific version of Python, remove the.venvfolder and setPYTHON_BINARYbefore runningjust install. - Ensure you have started the appropriate Mongo Server(s). You can run
just run-serverwith optional args to set up the server. All given options will be passed torun-orchestration.sh. Run$DRIVERS_TOOLS/evergreen/run-orchestration.sh -hfor a full list of options. - Run
just testorpytestto run all of the tests. - Append
test/<mod_name>.py::<class_name>::<test_name>to run specific tests. You can omit the<test_name>to test a full class and the<class_name>to test a full module. For example:just test test/test_change_stream.py::TestUnifiedChangeStreamsErrors::test_change_stream_errors_on_ElectionInProgress. - Use the
-kargument to select tests by pattern.
- Clone
drivers-evergreen-tools:git clone git@github.com:mongodb-labs/drivers-evergreen-tools.git. - Run
export DRIVERS_TOOLS=$PWD/drivers-evergreen-tools. This can be put into a.bashrcfile for convenience. - Some tests require access to Drivers test secrets.
- Run
just run-serverwith optional args to set up the server. - Run
just setup-testswith optional args to set up the test environment, secrets, etc. Seejust setup-tests -hfor a full list of available options. - Run
just run-teststo run the tests in an appropriate Python environment. - When done, run
just teardown-teststo clean up andjust stop-serverto stop the server.
- Run
just run-server --sslto start the server with TLS enabled. - Run
just setup-tests --ssl. - Run
just run-tests.
Note: for general testing purposes with an TLS-enabled server, you can use the following (this should ONLY be used for local testing):
from pymongo import MongoClient
client = MongoClient(
"mongodb://localhost:27017?tls=true&tlsAllowInvalidCertificates=true"
)If you want to use the actual certificate file then set tlsCertificateKeyFile to the local path
to <repo_roo>/test/certificates/client.pem and tlsCAFile to the local path to <repo_roo>/test/certificates/ca.pem.
- Run
just run-serverto start the server. - Run
just setup-tests encryption. - Run the tests with
just run-tests.
To test with encryption and PyOpenSSL, use just setup-tests encryption pyopenssl.
- Run
just run-serverto start the server. - Run
just setup-tests default_sync pyopenssl. - Run the tests with
just run-tests.
Note: PyOpenSSL is not used in async tests, but you can use just setup-tests default_async pyopenssl
to verify that PyMongo falls back to the standard library OpenSSL.
- Install
haproxy(available asbrew install haproxyon macOS). - Start the server with
just run-server load_balancer. - Set up the test with
just setup-tests load_balancer. - Run the tests with
just run-tests.
- Run
just run-server auth_awsto start the server. - Run
just setup-tests auth_aws <aws-test-type>to set up the AWS test. - Run the tests with
just run-tests.
- Run
just setup-tests auth_oidc <oidc-test-type>to set up the OIDC test. - Run the tests with
just run-tests.
The supported types are [default, azure, gcp, eks, aks, and gke].
For the eks test, you will need to set up access to the drivers-test-secrets-role, see the Wiki.
For KMS tests that are run locally, and expected to fail, in this case using azure:
- Run
just run-server. - Run
just setup-tests kms azure-fail. - Run
just run-tests.
For KMS tests that run remotely and are expected to pass, in this case using gcp:
- Run
just setup-tests kms gcp. - Run
just run-tests.
Note: these tests can only be run from an Evergreen host.
- Run
just run-server enterprise_auth. - Run
just setup-tests enterprise_auth. - Run
just run-tests.
- Run
just setup-tests atlas_connect. - Run
just run-tests.
- Run
just run-server search_index. - Run
just setup-tests search_index. - Run
just run-tests.
- Run
just setup-tests mockupdb. - Run
just run-tests.
The doc tests require a running server.
- Run
just run-server. - Run
just setup-tests doctest. - Run
just run-tests.
In the evergreen builds, the tests are configured to use the free-threaded python from the toolchain. Locally you can run:
- Run
just run-server. - Run
just setup-tests. - Run
UV_PYTHON=3.13t just run-tests.
You will need to set up access to the drivers-test-secrets-role, see the Wiki.
- Run
just setup-tests aws_lambda. - Run
just run-tests.
Note: these tests can only be run from an Evergreen Linux host that has the Python toolchain.
- Run
just run-server. - Run
just setup-tests mod_wsgi <mode>. - Run
just run-tests.
The mode can be standalone or embedded. For the replica_set version of the tests, use
TOPOLOGY=replica_set just run-server.
You must have docker or podman installed locally.
- Run
just setup-tests data_lake. - Run
just run-tests.
-
Export the orchestration file, e.g.
export ORCHESTRATION_FILE=rsa-basic-tls-ocsp-disableStapling.json. This corresponds to a config file in$DRIVERS_TOOLS/.evergreen/orchestration/configs/servers. MongoDB servers on MacOS and Windows do not staple OCSP responses and only support RSA. NOTE: because the mock ocsp responder MUST be started prior to the server starting, the ocsp tests start the server as part ofsetup-tests. -
Run
just setup-tests ocsp <sub test>(options are "valid", "revoked", "valid-delegate", "revoked-delegate"). -
Run
just run-tests
If you are running one of the no-responder tests, omit the run-server step.
- Start the appropriate server, e.g.
just run-server --version=v8.0-perf --ssl. - Set up the tests with
syncorasync:just setup-tests perf sync. - Run the tests:
just run-tests.
- Use
-o log_cli_level="DEBUG" -o log_cli=1withjust testorpytestto output all debug logs to the terminal. Warning: This will output a huge amount of logs. - Add
log_cli=1andlog_cli_level="DEBUG"to thetool.pytest.ini_optionssection inpyproject.tomlto enable debug logs in this manner by default on your machine. - Set
DEBUG_LOG=1and runjust setup-tests,just-test, orpytestto enable debug logs only for failed tests. - Finally, you can use
just setup-tests --debug-log. - For evergreen patch builds, you can use
evergreen patch --param DEBUG_LOG=1to enable debug logs for failed tests in the patch.
- If adding new tests files that should only be run for that test suite, add a pytest marker to the file and add
to the list of pytest markers in
pyproject.toml. Then add the test suite to theTEST_SUITE_MAPin.evergreen/scripts/utils.py. If for some reason it is not a pytest-runnable test, add it to the list ofEXTRA_TESTSinstead. - If the test uses Atlas or otherwise doesn't use
run-orchestration.sh, add it to theNO_RUN_ORCHESTRATIONlist in.evergreen/scripts/utils.py. - If there is something special required to run the local server or there is an extra flag that should always be set
like
AUTH, add that logic to.evergreen/scripts/run_server.py. - The bulk of the logic will typically be in
.evergreen/scripts/setup_tests.py. This is where you should fetch secrets and make them available usingwrite_env, start services, and write other env vars needed usingwrite_env. - If there are any special test considerations, including not running
pytestat all, handle it in.evergreen/scripts/run_tests.py. - If there are any services or atlas clusters to teardown, handle them in
.evergreen/scripts/teardown_tests.py. - Add functions to generate the test variant(s) and task(s) to the
.evergreen/scripts/generate_config.py. - Regenerate the test variants and tasks using
pre-commit run --all-files generate-config. - Make sure to add instructions for running the test suite to
CONTRIBUTING.md.
We have a custom flaky decorator in test/asynchronous/utils.py that can be used for
tests that are flaky. By default the decorator only applies when not running on CPython on Linux, since other
runtimes tend to have more variation. When using the flaky decorator, open a corresponding ticket and
a use the ticket number as the "reason" parameter to the decorator, e.g. @flaky(reason="PYTHON-1234").
When running tests locally (not in CI), the flaky decorator will be disabled unless ENABLE_FLAKY is set.
To disable the flaky decorator in CI, you can use evergreen patch --param DISABLE_FLAKY=1.
The MongoDB specifications repository holds in progress and completed specifications for features of MongoDB, drivers, and associated products. PyMongo supports the Unified Test Format for running specification tests to confirm PyMongo behaves as expected.
If you would like to re-sync the copy of the specification tests in the
PyMongo repository with that which is inside the specifications
repo, please use the script
provided in .evergreen/resync-specs.sh.:
git clone git@github.com:mongodb/specifications.git
export MDB_SPECS=~/specifications
cd ~/mongo-python-driver/.evergreen
./resync-specs.sh -b "<regex>" spec1 spec2 ...
./resync-specs.sh -b "connection-string*" crud bson-corpus # Updates crud and bson-corpus specs while ignoring all files with the regex "connection-string*"
cd ..The -b flag adds as a regex pattern to block files you do not wish to
update in PyMongo. This is primarily helpful if you are implementing a
new feature in PyMongo that has spec tests already implemented, or if
you are attempting to validate new spec tests in PyMongo.
The (/.evergreen/scripts/resync-all-specs.sh) script
automatically runs once a week to resync all the specs with the specifications repo.
A PR will be generated by mongodb-drivers-pr-bot containing any changes picked up by this resync.
The PR description will display the name(s) of the updated specs along
with any errors that occurred.
Spec test changes associated with a behavioral change or bugfix that has yet to be implemented in PyMongo
must be added to a patch file in /.evergreen/spec-patch. Each patch
file must be named after the associated PYTHON ticket and contain the
test differences between PyMongo's current tests and the specification.
All changes listed in these patch files will be undone by the script and won't
be applied to PyMongo's tests.
When a new test file or folder is added to the spec repo before the associated code changes are implemented, that test's path must be added to .evergreen/remove-unimplemented-tests.sh along with a comment indicating the associated PYTHON ticket for those changes.
Any PR that implements a PYTHON ticket documented in a patch file or within .evergreen/remove-unimplemented-tests.sh must also remove the associated patch file or entry in remove-unimplemented-tests.sh.
To add to or create a patch file, run git diff to show the desired changes to undo and copy the
results into the patch file.
For example: the imaginary, unimplemented PYTHON-1234 ticket has associated spec test changes. To add those changes to PYTHON-1234.patch), do the following:
git diff HEAD~1 path/to/file >> .evergreen/spec-patch/PYTHON-1234.patch
#### Running Locally
Both `resync-all-specs.sh` and `resync-all-specs.py` can be run locally (and won't generate a PR).
```bash
./.evergreen/scripts/resync-all-specs.sh
python3 ./.evergreen/scripts/resync-all-specs.pyFollow the Python Driver Release Process Wiki.
PyMongo adds asyncio capability by modifying the source files in */asynchronous to */synchronous using
unasync and some custom transforms.
Where possible, edit the code in */asynchronous/*.py and not the synchronous files.
You can run pre-commit run --all-files synchro before running tests if you are testing synchronous code.
To prevent the synchro hook from accidentally overwriting code, it first checks to see whether a sync version
of a file is changing and not its async counterpart, and will fail.
In the unlikely scenario that you want to override this behavior, first export OVERRIDE_SYNCHRO_CHECK=1.
Sometimes, the synchro hook will fail and introduce changes many previously unmodified files. This is due to static
Python errors, such as missing imports, incorrect syntax, or other fatal typos. To resolve these issues,
run pre-commit run --all-files --hook-stage manual ruff and fix all reported errors before running the synchro
hook again.
The tools/convert_test_to_async.py script takes in an existing synchronous test file and outputs a
partially-converted asynchronous version of the same name to the test/asynchronous directory.
Use this generated file as a starting point for the completed conversion.
The script is used like so: python tools/convert_test_to_async.py [test_file.py]
To profile a test script and generate a flame graph, follow these steps:
- Install
py-spyif you haven't already:pip install py-spy
- Inside your test script, perform any required setup and then loop over the code you want to profile for improved sampling.
- Run
py-spy record -o <output.svg> -r <sample_rate=100> -- python <path/to/script>to generate a.svgfile containing the flame graph. (Note: on macOS you will need to run this command usingsudoto allowpy-spyto attach to the Python process.) - If you need to include native code (for example the C extensions), profiling should be done on a Linux system, as macOS and Windows do not support the
--nativeoption ofpy-spy. Creating an ubuntu Evergreen spawn host and usingscpto copy the flamegraph.svgfile back to your local machine is the best way to do this.