diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..a9d726b96 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Global owner for repo +* @mongodb/dbx-python diff --git a/.github/workflows/release-python.yml b/.github/workflows/release-python.yml index 1bf2160df..e0c0ae02b 100644 --- a/.github/workflows/release-python.yml +++ b/.github/workflows/release-python.yml @@ -8,7 +8,6 @@ on: - "[0-9]+.[0-9]+.[0-9]+[a-b][0-9]+" - "[0-9]+.[0-9]+.[0-9]+rc[0-9]+" workflow_dispatch: - pull_request: concurrency: group: wheels-${{ github.ref }} diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index e9fb64336..fe5d530dc 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -15,13 +15,13 @@ defaults: jobs: - lint: + static: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: 3.8 + python-version: "3.8" cache: 'pip' cache-dependency-path: 'pyproject.toml' - name: Install Python dependencies @@ -30,7 +30,21 @@ jobs: - name: Run linters run: | tox -m lint-manual + - name: Check Manifest + run: | tox -m manifest + - name: Run compilation + run: | + pip install -e . + python tools/fail_if_no_c.py + - name: Run typecheck + run: | + tox -m typecheck + - run: | + sudo apt-get install -y cppcheck + - run: | + cppcheck --force bson + cppcheck pymongo build: # supercharge/mongodb-github-action requires containers so we don't test other platforms @@ -81,26 +95,6 @@ jobs: run: | tox -m doc-test - typing: - name: Typing Tests - runs-on: ubuntu-latest - strategy: - matrix: - python: ["3.7", "3.11"] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: "${{matrix.python}}" - cache: 'pip' - cache-dependency-path: 'pyproject.toml' - - name: Install dependencies - run: | - pip install -q tox - - name: Run typecheck - run: | - tox -m typecheck - docs: name: Docs Checks runs-on: ubuntu-latest @@ -122,6 +116,44 @@ jobs: run: | tox -m doc + linkcheck: + name: Link Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + cache: 'pip' + cache-dependency-path: 'pyproject.toml' + # Build docs on lowest supported Python for furo + python-version: '3.8' + - name: Install dependencies + run: | + pip install -q tox + - name: Build docs + run: | + tox -m linkcheck + + typing: + name: Typing Tests + runs-on: ubuntu-latest + strategy: + matrix: + python: ["3.7", "3.11"] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "${{matrix.python}}" + cache: 'pip' + cache-dependency-path: 'pyproject.toml' + - name: Install dependencies + run: | + pip install -q tox + - name: Run typecheck + run: | + tox -m typecheck + make_sdist: runs-on: ubuntu-latest name: "Make an sdist" diff --git a/bson/datetime_ms.py b/bson/datetime_ms.py index 160f63faa..112871a16 100644 --- a/bson/datetime_ms.py +++ b/bson/datetime_ms.py @@ -51,7 +51,7 @@ class DatetimeMS: encoding/decoding BSON. To decode UTC datetimes as a ``DatetimeMS``, `datetime_conversion` in - :class:`~bson.CodecOptions` must be set to 'datetime_ms' or + :class:`~bson.codec_options.CodecOptions` must be set to 'datetime_ms' or 'datetime_auto'. See :ref:`handling-out-of-range-datetimes` for details. diff --git a/doc/migrate-to-pymongo4.rst b/doc/migrate-to-pymongo4.rst index 35fc922d5..f751b4181 100644 --- a/doc/migrate-to-pymongo4.rst +++ b/doc/migrate-to-pymongo4.rst @@ -328,13 +328,13 @@ Removed :meth:`pymongo.database.Database.collection_names`. Use :meth:`~pymongo.database.Database.list_collection_names` instead. Code like this:: - names = client.collection_names() - non_system_names = client.collection_names(include_system_collections=False) + names = client.db.collection_names() + non_system_names = client.db.collection_names(include_system_collections=False) can be changed to this:: - names = client.list_collection_names() - non_system_names = client.list_collection_names(filter={"name": {"$regex": r"^(?!system\\.)"}}) + names = client.db.list_collection_names() + non_system_names = client.db.list_collection_names(filter={"name": {"$regex": "^(?!system\\.)"}}) Database.current_op is removed .............................. diff --git a/gridfs/grid_file.py b/gridfs/grid_file.py index 971170c6c..ac72c144b 100644 --- a/gridfs/grid_file.py +++ b/gridfs/grid_file.py @@ -19,6 +19,7 @@ import datetime import io import math import os +import warnings from typing import Any, Iterable, Mapping, NoReturn, Optional from bson.int64 import Int64 @@ -69,8 +70,15 @@ def _grid_in_property( closed_only: Optional[bool] = False, ) -> Any: """Create a GridIn property.""" + warn_str = "" + if docstring.startswith("DEPRECATED,"): + warn_str = ( + f"GridIn property '{field_name}' is deprecated and will be removed in PyMongo 5.0" + ) def getter(self: Any) -> Any: + if warn_str: + warnings.warn(warn_str, stacklevel=2, category=DeprecationWarning) if closed_only and not self._closed: raise AttributeError("can only get %r on a closed file" % field_name) # Protect against PHP-237 @@ -79,6 +87,8 @@ def _grid_in_property( return self._file.get(field_name, None) def setter(self: Any, value: Any) -> Any: + if warn_str: + warnings.warn(warn_str, stacklevel=2, category=DeprecationWarning) if self._closed: self._coll.files.update_one({"_id": self._file["_id"]}, {"$set": {field_name: value}}) self._file[field_name] = value @@ -100,8 +110,15 @@ def _grid_in_property( def _grid_out_property(field_name: str, docstring: str) -> Any: """Create a GridOut property.""" + warn_str = "" + if docstring.startswith("DEPRECATED,"): + warn_str = ( + f"GridOut property '{field_name}' is deprecated and will be removed in PyMongo 5.0" + ) def getter(self: Any) -> Any: + if warn_str: + warnings.warn(warn_str, stacklevel=2, category=DeprecationWarning) self._ensure_file() # Protect against PHP-237 diff --git a/pymongo/collection.py b/pymongo/collection.py index da1a79966..ddfe9f1df 100644 --- a/pymongo/collection.py +++ b/pymongo/collection.py @@ -114,7 +114,6 @@ class ReturnDocument: if TYPE_CHECKING: - import bson from pymongo.aggregation import _AggregationCommand from pymongo.client_session import ClientSession from pymongo.collation import Collation @@ -420,7 +419,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): def with_options( self, - codec_options: Optional[bson.CodecOptions[_DocumentTypeArg]] = None, + codec_options: Optional[CodecOptions[_DocumentTypeArg]] = None, read_preference: Optional[_ServerMode] = None, write_concern: Optional[WriteConcern] = None, read_concern: Optional[ReadConcern] = None, diff --git a/pymongo/database.py b/pymongo/database.py index a80897e3f..70580694e 100644 --- a/pymongo/database.py +++ b/pymongo/database.py @@ -76,7 +76,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): self, client: MongoClient[_DocumentType], name: str, - codec_options: Optional[bson.CodecOptions[_DocumentTypeArg]] = None, + codec_options: Optional[CodecOptions[_DocumentTypeArg]] = None, read_preference: Optional[_ServerMode] = None, write_concern: Optional[WriteConcern] = None, read_concern: Optional[ReadConcern] = None, @@ -154,7 +154,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): def with_options( self, - codec_options: Optional[bson.CodecOptions[_DocumentTypeArg]] = None, + codec_options: Optional[CodecOptions[_DocumentTypeArg]] = None, read_preference: Optional[_ServerMode] = None, write_concern: Optional[WriteConcern] = None, read_concern: Optional[ReadConcern] = None, @@ -238,7 +238,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): def get_collection( self, name: str, - codec_options: Optional[bson.CodecOptions[_DocumentTypeArg]] = None, + codec_options: Optional[CodecOptions[_DocumentTypeArg]] = None, read_preference: Optional[_ServerMode] = None, write_concern: Optional[WriteConcern] = None, read_concern: Optional[ReadConcern] = None, @@ -320,7 +320,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): def create_collection( self, name: str, - codec_options: Optional[bson.CodecOptions[_DocumentTypeArg]] = None, + codec_options: Optional[CodecOptions[_DocumentTypeArg]] = None, read_preference: Optional[_ServerMode] = None, write_concern: Optional[WriteConcern] = None, read_concern: Optional[ReadConcern] = None, diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 3de95a7f5..9bead2988 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -55,8 +55,7 @@ from typing import ( cast, ) -import bson -from bson.codec_options import DEFAULT_CODEC_OPTIONS, TypeRegistry +from bson.codec_options import DEFAULT_CODEC_OPTIONS, CodecOptions, TypeRegistry from bson.timestamp import Timestamp from pymongo import ( _csot, @@ -2032,7 +2031,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): def get_default_database( self, default: Optional[str] = None, - codec_options: Optional[bson.CodecOptions[_DocumentTypeArg]] = None, + codec_options: Optional[CodecOptions[_DocumentTypeArg]] = None, read_preference: Optional[_ServerMode] = None, write_concern: Optional[WriteConcern] = None, read_concern: Optional[ReadConcern] = None, @@ -2092,7 +2091,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): def get_database( self, name: Optional[str] = None, - codec_options: Optional[bson.CodecOptions[_DocumentTypeArg]] = None, + codec_options: Optional[CodecOptions[_DocumentTypeArg]] = None, read_preference: Optional[_ServerMode] = None, write_concern: Optional[WriteConcern] = None, read_concern: Optional[ReadConcern] = None, diff --git a/pyproject.toml b/pyproject.toml index 3cdb03a1b..40c564689 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,6 +115,8 @@ filterwarnings = [ "module:Unsupported compressor:UserWarning", "module:zlibcompressionlevel must be:UserWarning", "module:Wire protocol compression with:UserWarning", + "module:GridIn property:DeprecationWarning", + "module:GridOut property:DeprecationWarning", # TODO: Remove as part of PYTHON-3923. "module:unclosed