[build-system]
requires = ["hatchling>1.24","setuptools>=65.0","hatch-requirements-txt>=0.4.1"]
build-backend = "hatchling.build"

[project]
name = "pymongo"
dynamic = ["version", "dependencies", "optional-dependencies"]
description = "PyMongo - the Official MongoDB Python driver"
readme = "README.md"
license = {file="LICENSE"}
requires-python = ">=3.9"
authors = [
    { name = "The MongoDB Python Team" },
]
keywords = [
    "bson",
    "gridfs",
    "mongo",
    "mongodb",
    "pymongo",
]
classifiers = [
    "Development Status :: 5 - Production/Stable",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: Apache Software License",
    "Operating System :: MacOS :: MacOS X",
    "Operating System :: Microsoft :: Windows",
    "Operating System :: POSIX",
    "Programming Language :: Python :: Implementation :: CPython",
    "Programming Language :: Python :: Implementation :: PyPy",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3 :: Only",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Topic :: Database",
    "Typing :: Typed",
]

[project.urls]
Homepage = "https://www.mongodb.org"
Documentation = "https://www.mongodb.com/docs/languages/python/pymongo-driver/current/"
Source = "https://github.com/mongodb/mongo-python-driver"
Tracker = "https://jira.mongodb.org/projects/PYTHON/issues"

[dependency-groups]
dev = [
    "pre-commit>=4.0"
]
pip = ["pip"]
# TODO: PYTHON-5464
gevent = ["gevent", "cffi>=2.0.0b1;python_version=='3.14'"]
eventlet = ["eventlet"]
coverage = [
    "pytest-cov",
    "coverage>=5,<=7.10.2"
]
mockupdb = [
    "mockupdb@git+https://github.com/mongodb-labs/mongo-mockup-db@master"
]
pymongocrypt_source = [
    "pymongocrypt@git+https://github.com/mongodb/libmongocrypt@master#subdirectory=bindings/python"
]
perf = ["simplejson"]
typing = [
    "mypy==1.17.1",
    "pyright==1.1.403",
    "typing_extensions",
    "pip"
]

# Used to call hatch_build.py
[tool.hatch.build.hooks.custom]

[tool.hatch.version]
path = "pymongo/_version.py"
validate-bump = false

[tool.hatch.build.targets.wheel]
packages = ["bson","gridfs", "pymongo"]

[tool.hatch.metadata.hooks.requirements_txt]
files = ["requirements.txt"]

[tool.hatch.metadata.hooks.requirements_txt.optional-dependencies]
aws = ["requirements/aws.txt"]
docs = ["requirements/docs.txt"]
encryption = ["requirements/encryption.txt"]
gssapi = ["requirements/gssapi.txt"]
ocsp = ["requirements/ocsp.txt"]
snappy = ["requirements/snappy.txt"]
test = ["requirements/test.txt"]
zstd = ["requirements/zstd.txt"]

[tool.pytest.ini_options]
minversion = "7"
addopts = ["-ra", "--strict-config", "--strict-markers", "--junitxml=xunit-results/TEST-results.xml", "-m default or default_async"]
testpaths = ["test"]
log_cli_level = "INFO"
faulthandler_timeout = 1500
asyncio_default_fixture_loop_scope = "session"
xfail_strict = true
filterwarnings = [
    "error",
    # Internal warnings raised during tests.
    "module:use an explicit session with no_cursor_timeout=True:UserWarning",
    "module:serverselectiontimeoutms must be:UserWarning",
    "module:Unsupported compressor:UserWarning",
    "module:zlibcompressionlevel must be:UserWarning",
    "module:Wire protocol compression with:UserWarning",
    "module:GridIn property:DeprecationWarning",
    "module:GridOut property:DeprecationWarning",
    # pytest-asyncio known issue: https://github.com/pytest-dev/pytest-asyncio/issues/1032
    "module:.*WindowsSelectorEventLoopPolicy:DeprecationWarning",
    "module:.*et_event_loop_policy:DeprecationWarning",
    # TODO: Remove as part of PYTHON-3923.
    "module:unclosed <eventlet.green.ssl.GreenSSLSocket:ResourceWarning",
    "module:unclosed <socket.socket:ResourceWarning",
    "module:unclosed <ssl.SSLSocket:ResourceWarning",
    "module:unclosed <socket object:ResourceWarning",
    "module:unclosed transport:ResourceWarning",
    # pytest-asyncio known issue: https://github.com/pytest-dev/pytest-asyncio/issues/724
    "module:unclosed event loop:ResourceWarning",
    # https://github.com/eventlet/eventlet/issues/818
    "module:please use dns.resolver.Resolver.resolve:DeprecationWarning",
    # https://github.com/dateutil/dateutil/issues/1314
    "module:datetime.datetime.utc:DeprecationWarning",
]
markers = [
    "auth_aws: tests that rely on pymongo-auth-aws",
    "auth_oidc: tests that rely on oidc auth",
    "auth: tests that rely on authentication",
    "ocsp: tests that rely on ocsp",
    "atlas_connect: tests that rely on an atlas connection",
    "data_lake: tests that rely on atlas data lake",
    "perf: benchmark tests",
    "search_index: search index helper tests",
    "kms: client-side field-level encryption tests using kms",
    "encryption: encryption tests",
    "load_balancer: load balancer tests",
    "mockupdb: tests that rely on mockupdb",
    "default: default test suite",
    "default_async: default async test suite",
]

[tool.mypy]
strict = true
show_error_codes = true
pretty = true
disable_error_code = ["type-arg", "no-any-return"]

[[tool.mypy.overrides]]
module = ["test.*"]
disable_error_code = ["no-untyped-def", "no-untyped-call"]

[[tool.mypy.overrides]]
module = ["service_identity.*"]
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = ["pymongo.synchronous.*"]
warn_unused_ignores = false
disable_error_code = ["unused-coroutine"]

[[tool.mypy.overrides]]
module = ["pymongo.asynchronous.*"]
warn_unused_ignores = false

[[tool.mypy.overrides]]
module = ["gridfs.synchronous.*"]
warn_unused_ignores = false
disable_error_code = ["unused-coroutine", "no-redef"]

[tool.ruff]
target-version = "py37"
line-length = 100

[tool.ruff.lint]
select = [
  "E", "F", "W", # flake8
  "B",           # flake8-bugbear
  "I",           # isort
  "ARG",         # flake8-unused-arguments
  "C4",          # flake8-comprehensions
  "EM",          # flake8-errmsg
  "ICN",         # flake8-import-conventions
  "G",           # flake8-logging-format
  "PGH",         # pygrep-hooks
  "PIE",         # flake8-pie
  "PL",          # pylint
  "PT",          # flake8-pytest-style
  "PTH",         # flake8-use-pathlib
  "RET",         # flake8-return
  "RUF",         # Ruff-specific
  "S",           # flake8-bandit
  "SIM",         # flake8-simplify
  "T20",         # flake8-print
  "UP",          # pyupgrade
  "YTT",         # flake8-2020
  "EXE",         # flake8-executable
  "ASYNC",       # flake8-async
]
ignore = [
  "PLR",    # Design related pylint codes
  "E501",   # Line too long
  "PT004",  # Use underscore for non-returning fixture (use usefixture instead)
  "UP007",  # Use `X | Y` for type annotation
  "EM101",  # Exception must not use a string literal, assign to variable first
  "EM102",  # Exception must not use an f-string literal, assign to variable first
  "G004",   # Logging statement uses f-string"
  "UP006",  # Use `type` instead of `Type` for type annotation"
  "RET505", # Unnecessary `elif` after `return` statement"
  "RET506", # Unnecessary `elif` after `raise` statement
  "SIM108", # Use ternary operator"
  "PTH123", # `open()` should be replaced by `Path.open()`"
  "SIM102", # Use a single `if` statement instead of nested `if` statements
  "SIM105", # Use `contextlib.suppress(OSError)` instead of `try`-`except`-`pass`
  "ARG002", # Unused method argument:
  "S101",   # Use of `assert` detected
  "SIM114", # Combine `if` branches using logical `or` operator
  "PGH003", # Use specific rule codes when ignoring type issues
  "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
  "EM103",  # Exception must not use a `.format()` string directly, assign to variable first
  "C408",   # Unnecessary `dict` call (rewrite as a literal)
  "SIM117", # Use a single `with` statement with multiple contexts instead of nested `with` statements
]
unfixable = [
  "RUF100", # Unused noqa
  "T20",  # Removes print statements
  "F841", # Removes unused variables
]
exclude = []
flake8-unused-arguments.ignore-variadic-names = true
isort.required-imports = ["from __future__ import annotations"]
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?)|dummy.*)$"

[tool.ruff.lint.per-file-ignores]
"pymongo/__init__.py" = ["E402"]
"test/*.py" = ["PT", "E402", "PLW", "SIM", "E741", "PTH", "S", "B904", "E722", "T201",
    "RET", "ARG", "F405", "B028", "PGH001", "B018", "F403", "RUF015", "E731", "B007",
    "UP031", "F401", "B023", "F811"]
"tools/*.py" = ["T201"]
"hatch_build.py" = ["S"]
"_setup.py" = ["SIM112"]

[tool.coverage.run]
branch = true
source = ["pymongo", "bson", "gridfs" ]
relative_files = true

[tool.coverage.report]
exclude_lines = [
    "if (.*and +)*_use_c( and.*)*:",
    "def has_c",
    "def get_version_string",
    "^except AttributeError:",
    "except ImportError:",
    "raise NotImplementedError",
    "return NotImplemented",
    "_use_c = true",
    "if __name__ == '__main__':",
    "if TYPE_CHECKING:"
    ]
partial_branches = ["if (.*and +)*not _use_c( and.*)*:"]

[tool.coverage.html]
directory = "htmlcov"

[tool.cibuildwheel]
# Enable free-threaded support
free-threaded-support = true
skip = "pp* *-musllinux*"
build-frontend = "build"
test-command = "python {project}/tools/fail_if_no_c.py"

[tool.cibuildwheel.linux]
archs = "x86_64 aarch64 ppc64le s390x i686"
[tool.cibuildwheel.macos]
archs = "x86_64 arm64"
