This document describes the common coding standards for all projects maintained by the Python Drivers team. These standards apply to all written code, comments, and docstrings, both human and machine-authored. Use these guidelines both when writing and reviewing code.
This is a living document: when an issue or difference of opinion occurs several times across reviews or designs, the final resolution should be added as a new guiding rule here.
- Comments provide additional context for code when that context is not apparent in the code itself. Code that is self-explanatory should never have a comment.
- A good comment:
# SSLSocket can have buffered data which won't be caught by select.
if hasattr(sock, "pending") and sock.pending() > 0:
readable = True- An unnecessary comment:
# Check if the socket is pending.
if hasattr(sock, "pending") and sock.pending() > 0:
readable = True- Comments are concise.
- Comments use proper English grammar: start with a capital letter, use correct punctuation, and end with a period.
- Avoid metaphors, similes, analogies, and other figurative language.
- Follow PEP 257’s conventions alongside the following example Sphinx formatting (this is for AsyncCollection.distinct()):
"""Get a list of distinct values for `key` among all documents
in this collection.
Raises :class:`TypeError` if `key` is not an instance of
:class:`str`.
All optional distinct parameters should be passed as keyword arguments
to this method. Valid options include:
- `maxTimeMS` (int): The maximum amount of time to allow the count
command to run, in milliseconds.
- `collation` (optional): An instance of
:class:`~pymongo.collation.Collation`.
The :meth:`distinct` method obeys the :attr:`read_preference` of
this :class:`AsyncCollection`.
:param key: Name of the field for which we want to get the distinct
values.
:param filter: A query document that specifies the documents
from which to retrieve the distinct values.
:param session: A
:class:`~pymongo.asynchronous.client_session.AsyncClientSession`.
:param comment: A user-provided comment to attach to this
command.
:param hint: An index to use to support the query
predicate specified either by its string name, or in the same
format as passed to :meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index`
(e.g. ``[('field', ASCENDING)]``).
:param kwargs: See list of options above.
.. versionchanged:: 4.12
Added ``hint`` parameter.
.. versionchanged:: 3.6
Added ``session`` parameter.
.. versionchanged:: 3.4
Support the `collation` option.
"""- Docstrings tell the reader the purpose and behavior of an API. They do not describe internal implementation details.
- Include what errors can be raised from the API.
- Follow PEP 8’s conventions, mostly enforced by ruff and pre-commit. Note that we use a line length of 100 characters rather than 79.
- Avoid magic numbers.
- Prefer shared helpers and abstraction over code duplication.
- Bias towards less code.
- Use consistent patterns for similar code.
- Consider race conditions.
- Handle or explicitly rule out edge cases with a comment if the reason is non-obvious or undocumented.
- Prioritize future maintainability. If you would be unhappy maintaining a piece of code five years in the future, do not commit it.
- When updating a method or class with multiple arguments, append the argument name unless strictly necessary.
- Raise or catch specific rather than general error types:
# Do this
except OperationFailure:
...
# Not this
except PyMongoError:
...
# Not this
except OperationFailure:
raise Exception(...)- Use “raise … from …” syntax when chaining errors.
- Avoid doing unnecessary work: if an operation can be avoided in certain conditions, check those conditions before performing it.
- Do this:
if value == "abc":
return
result = expensive_function_call(value)
if result == ...- Avoid this:
result = expensive_function_call(value)
if value == "abc":
return
if result == ...- Hold locks only for the minimal critical section.
- Run the performance benchmarking suite to catch possible regressions for large feature or performance changes.
- All tests should pass; if one does not pass and you can prove that it is unrelated to your current changes, note the failure in your PR before merging.
- All code reachable through a public API must have test coverage.
- Prefer many small tests over one large one.
- Use unittest-style assertions when using unittest.
- Setup and cleanup test resources safely for both success and failure.
- Prefer unit tests instead of integration tests where possible.
- Annotate public APIs and verify using “mypy --strict”.
- Type-only dependencies should be imported within a TYPE_CHECKING block:
from pymongo import MongoClient
if TYPE_CHECKING:
from pymongo.collection import Collection- We support all of the currently maintained CPython versions. All code must be compatible with the oldest supported version, which is 3.11 as of October 2026.
- Avoid breaking changes when possible.
- Follow semantic versioning guidelines.
- When deprecating a public API, add a deprecation warning to every call, a “deprecated::” line in its docstring, and a note in the changelog of the deprecating release.
- Changes marked
deprecated::get removed in the next major release
- Changes marked
- All user-facing changes require a changelog entry.
- Changelog entries are concise summaries of their described changes written using proper English grammar and in the past tense.
- Changelog entries must start with one of the following words that categorize the type of change:
Added: new features.Changed: changes in existing functionality.Deprecated: features to be removed in a future version.Removed: features removed in the described version.Fixed: bug fixes.Security: patched vulnerabilities.
- Group all entries of the same type together in each version.
- Changelog entries do not contain implementation details.
- Use the guiding principle of "what would a user want to know about this" when describing a change.
- Changelog entries must end with a link to the JIRA ticket that implemented their changes.
- Cross-references to code must use one of the following Sphinx roles:
:meth:: methods.:class:: classes.:attr:: attributes and properties.:mod:: modules.:exc:: exceptions.:func:: functions.:data:: module-level variables.:const:: constants.
- Code snippets that do not fit any of the above roles must be contained within double backticks:
text.
- Commit messages are concise summaries of their described changes.
- Commit messages use proper English grammar except they do not end with a period.
- Commit messages are written in the imperative mood: they complete the sentence “this commit will …”.
- A good commit message: “Improve insert performance for large documents”
- A poor commit message: “2x speedup on inserts (if document > 1MB).”
- Extended messages longer than the one line summary are permitted, but are not encouraged as they are squashed during pull-request merge. They may contain periods.
- Do not force-push to an open PR unless absolutely necessary.