Users configuring MongoClient from environment variables or .env files currently do it by hand: os.environ.get(...), manual type coercion, no validation. This proposes an optional, typed, validated settings layer built on pydantic-settings, shipped as an opt-in extra so it never becomes a hard dependency for users who don't want pydantic.
New module: pymongo/pydantic_settings.py
(named to avoid colliding with the existing internal pymongo/synchronous/settings.py / pymongo/asynchronous/settings.py, which are unrelated ClientOptions/topology internals)
class MongoDBSettings(BaseSettings):
model_config = SettingsConfigDict(
env_prefix="MONGODB_", env_file=".env", extra="ignore"
)
uri: Optional[str] = None
host: str = "localhost"
port: int = 27017
username: Optional[str] = None
password: Optional[SecretStr] = None
database: Optional[str] = None # not a MongoClient kwarg; convenience for get_database()
replica_set: Optional[str] = None
tls: bool = False
tls_ca_file: Optional[str] = None
tls_certificate_key_file: Optional[str] = None
auth_source: Optional[str] = None
app_name: Optional[str] = None
direct_connection: Optional[bool] = None
def to_kwargs(self) -> dict[str, Any]:
...Env vars: MONGODB_URI, MONGODB_HOST, MONGODB_PORT, etc. This matches the MONGODB_URI convention already used throughout this repo's own test suite and Evergreen scripts, and the convention used across MongoDB driver spec-test runners generally.
If MONGODB_URI (or uri=) is set, to_kwargs() passes it straight through as host, plus any individual curated fields that are explicitly set (non-default), passed alongside as their own kwargs. No parsing or shadow-detection logic lives in the settings extra - MongoClient's own connection-string handling already does the merge: explicit kwargs override matching URI-embedded options, and anything the URI doesn't specify (like tls) comes through from the individual field untouched.
If no MONGODB_URI is set, to_kwargs() builds the dict entirely from the individual curated fields.
database is never included in to_kwargs() - it's a separate convenience attribute for client.get_database(settings.database).
Decoupled from client construction. MongoDBSettings only produces to_kwargs(); the caller decides which client class to instantiate:
client = MongoClient(**settings.to_kwargs())
# or
client = AsyncMongoClient(**settings.to_kwargs())One settings class serves both sync and async clients.
pydantic_settings is imported inside a try/except, following the existing pattern in pymongo/compression_support.py for other optional extras (e.g. zstd, snappy). If the extra isn't installed, importing pymongo.pydantic_settings raises a clear ImportError pointing at pip install pymongo[settings]. pydantic-settings is not a hard dependency of core PyMongo.
- New
requirements/settings.txtcontainingpydantic-settings>=2.0 - New entry in
pyproject.toml's[tool.hatch.metadata.hooks.requirements_txt.optional-dependencies]:settings = ["requirements/settings.txt"]
Unit tests only - no live MongoDB server required:
- env var parsing and type coercion
.envfile loadingto_kwargs()output for URI-only, individual-fields-only, and combined cases- field-to-kwarg name mapping (including
SecretStrunwrapping) - clear
ImportErrormessage when the extra isn't installed
- No full mirror of every
MongoClientconstructor kwarg - curated fields cover the common env-var-driven case (YAGNI) - No built-in client construction helper (e.g. no
settings.create_client()) - No pydantic v1 support -
pydantic-settingsv2 requires pydantic v2