diff --git a/bson/__init__.py b/bson/__init__.py index fc6efe0d59..790ac06ef1 100644 --- a/bson/__init__.py +++ b/bson/__init__.py @@ -1386,7 +1386,7 @@ def is_valid(bson: bytes) -> bool: :param bson: the data to be validated """ if not isinstance(bson, bytes): - raise TypeError("BSON data must be an instance of a subclass of bytes") + raise TypeError(f"BSON data must be an instance of a subclass of bytes, not {type(bson)}") try: _bson_to_dict(bson, DEFAULT_CODEC_OPTIONS) diff --git a/bson/binary.py b/bson/binary.py index f90dce226c..aab59cccbc 100644 --- a/bson/binary.py +++ b/bson/binary.py @@ -290,7 +290,7 @@ def __new__( subtype: int = BINARY_SUBTYPE, ) -> Binary: if not isinstance(subtype, int): - raise TypeError("subtype must be an instance of int") + raise TypeError(f"subtype must be an instance of int, not {type(subtype)}") if subtype >= 256 or subtype < 0: raise ValueError("subtype must be contained in [0, 256)") # Support any type that implements the buffer protocol. @@ -321,7 +321,7 @@ def from_uuid( .. versionadded:: 3.11 """ if not isinstance(uuid, UUID): - raise TypeError("uuid must be an instance of uuid.UUID") + raise TypeError(f"uuid must be an instance of uuid.UUID, not {type(uuid)}") if uuid_representation not in ALL_UUID_REPRESENTATIONS: raise ValueError( @@ -470,7 +470,7 @@ def as_vector(self) -> BinaryVector: """ if self.subtype != VECTOR_SUBTYPE: - raise ValueError(f"Cannot decode subtype {self.subtype} as a vector.") + raise ValueError(f"Cannot decode subtype {self.subtype} as a vector") position = 0 dtype, padding = struct.unpack_from(" Code: if not isinstance(code, str): - raise TypeError("code must be an instance of str") + raise TypeError(f"code must be an instance of str, not {type(code)}") self = str.__new__(cls, code) @@ -67,7 +67,7 @@ def __new__( if scope is not None: if not isinstance(scope, _Mapping): - raise TypeError("scope must be an instance of dict") + raise TypeError(f"scope must be an instance of dict, not {type(scope)}") if self.__scope is not None: self.__scope.update(scope) # type: ignore else: diff --git a/bson/codec_options.py b/bson/codec_options.py index 3a0b83b7be..258a777a1b 100644 --- a/bson/codec_options.py +++ b/bson/codec_options.py @@ -401,17 +401,23 @@ def __new__( "uuid_representation must be a value from bson.binary.UuidRepresentation" ) if not isinstance(unicode_decode_error_handler, str): - raise ValueError("unicode_decode_error_handler must be a string") + raise ValueError( + f"unicode_decode_error_handler must be a string, not {type(unicode_decode_error_handler)}" + ) if tzinfo is not None: if not isinstance(tzinfo, datetime.tzinfo): - raise TypeError("tzinfo must be an instance of datetime.tzinfo") + raise TypeError( + f"tzinfo must be an instance of datetime.tzinfo, not {type(tzinfo)}" + ) if not tz_aware: raise ValueError("cannot specify tzinfo without also setting tz_aware=True") type_registry = type_registry or TypeRegistry() if not isinstance(type_registry, TypeRegistry): - raise TypeError("type_registry must be an instance of TypeRegistry") + raise TypeError( + f"type_registry must be an instance of TypeRegistry, not {type(type_registry)}" + ) return tuple.__new__( cls, diff --git a/bson/dbref.py b/bson/dbref.py index 6c21b8162c..40bdb73cff 100644 --- a/bson/dbref.py +++ b/bson/dbref.py @@ -56,9 +56,9 @@ def __init__( .. seealso:: The MongoDB documentation on `dbrefs `_. """ if not isinstance(collection, str): - raise TypeError("collection must be an instance of str") + raise TypeError(f"collection must be an instance of str, not {type(collection)}") if database is not None and not isinstance(database, str): - raise TypeError("database must be an instance of str") + raise TypeError(f"database must be an instance of str, not {type(database)}") self.__collection = collection self.__id = id diff --git a/bson/decimal128.py b/bson/decimal128.py index 016afb5eb8..92c054d878 100644 --- a/bson/decimal128.py +++ b/bson/decimal128.py @@ -277,7 +277,7 @@ def from_bid(cls: Type[Decimal128], value: bytes) -> Decimal128: point in Binary Integer Decimal (BID) format). """ if not isinstance(value, bytes): - raise TypeError("value must be an instance of bytes") + raise TypeError(f"value must be an instance of bytes, not {type(value)}") if len(value) != 16: raise ValueError("value must be exactly 16 bytes") return cls((_UNPACK_64(value[8:])[0], _UNPACK_64(value[:8])[0])) # type: ignore diff --git a/bson/timestamp.py b/bson/timestamp.py index 3e76e7baad..949bd7b36c 100644 --- a/bson/timestamp.py +++ b/bson/timestamp.py @@ -58,9 +58,9 @@ def __init__(self, time: Union[datetime.datetime, int], inc: int) -> None: time = time - offset time = int(calendar.timegm(time.timetuple())) if not isinstance(time, int): - raise TypeError("time must be an instance of int") + raise TypeError(f"time must be an instance of int, not {type(time)}") if not isinstance(inc, int): - raise TypeError("inc must be an instance of int") + raise TypeError(f"inc must be an instance of int, not {type(inc)}") if not 0 <= time < UPPERBOUND: raise ValueError("time must be contained in [0, 2**32)") if not 0 <= inc < UPPERBOUND: diff --git a/gridfs/asynchronous/grid_file.py b/gridfs/asynchronous/grid_file.py index a49d51d304..d15713c51b 100644 --- a/gridfs/asynchronous/grid_file.py +++ b/gridfs/asynchronous/grid_file.py @@ -100,7 +100,7 @@ def __init__(self, database: AsyncDatabase, collection: str = "fs"): .. seealso:: The MongoDB documentation on `gridfs `_. """ if not isinstance(database, AsyncDatabase): - raise TypeError("database must be an instance of Database") + raise TypeError(f"database must be an instance of Database, not {type(database)}") database = _clear_entity_type_registry(database) @@ -503,7 +503,7 @@ def __init__( .. seealso:: The MongoDB documentation on `gridfs `_. """ if not isinstance(db, AsyncDatabase): - raise TypeError("database must be an instance of AsyncDatabase") + raise TypeError(f"database must be an instance of AsyncDatabase, not {type(db)}") db = _clear_entity_type_registry(db) @@ -1082,7 +1082,9 @@ def __init__( :attr:`~pymongo.collection.AsyncCollection.write_concern` """ if not isinstance(root_collection, AsyncCollection): - raise TypeError("root_collection must be an instance of AsyncCollection") + raise TypeError( + f"root_collection must be an instance of AsyncCollection, not {type(root_collection)}" + ) if not root_collection.write_concern.acknowledged: raise ConfigurationError("root_collection must use acknowledged write_concern") @@ -1436,7 +1438,9 @@ def __init__( from the server. Metadata is fetched when first needed. """ if not isinstance(root_collection, AsyncCollection): - raise TypeError("root_collection must be an instance of AsyncCollection") + raise TypeError( + f"root_collection must be an instance of AsyncCollection, not {type(root_collection)}" + ) _disallow_transactions(session) root_collection = _clear_entity_type_registry(root_collection) diff --git a/gridfs/synchronous/grid_file.py b/gridfs/synchronous/grid_file.py index 655f05f57a..ea0b53cfb7 100644 --- a/gridfs/synchronous/grid_file.py +++ b/gridfs/synchronous/grid_file.py @@ -100,7 +100,7 @@ def __init__(self, database: Database, collection: str = "fs"): .. seealso:: The MongoDB documentation on `gridfs `_. """ if not isinstance(database, Database): - raise TypeError("database must be an instance of Database") + raise TypeError(f"database must be an instance of Database, not {type(database)}") database = _clear_entity_type_registry(database) @@ -501,7 +501,7 @@ def __init__( .. seealso:: The MongoDB documentation on `gridfs `_. """ if not isinstance(db, Database): - raise TypeError("database must be an instance of Database") + raise TypeError(f"database must be an instance of Database, not {type(db)}") db = _clear_entity_type_registry(db) @@ -1076,7 +1076,9 @@ def __init__( :attr:`~pymongo.collection.Collection.write_concern` """ if not isinstance(root_collection, Collection): - raise TypeError("root_collection must be an instance of Collection") + raise TypeError( + f"root_collection must be an instance of Collection, not {type(root_collection)}" + ) if not root_collection.write_concern.acknowledged: raise ConfigurationError("root_collection must use acknowledged write_concern") @@ -1426,7 +1428,9 @@ def __init__( from the server. Metadata is fetched when first needed. """ if not isinstance(root_collection, Collection): - raise TypeError("root_collection must be an instance of Collection") + raise TypeError( + f"root_collection must be an instance of Collection, not {type(root_collection)}" + ) _disallow_transactions(session) root_collection = _clear_entity_type_registry(root_collection) diff --git a/pymongo/__init__.py b/pymongo/__init__.py index 58f6ff338b..8d6def1606 100644 --- a/pymongo/__init__.py +++ b/pymongo/__init__.py @@ -160,7 +160,7 @@ def timeout(seconds: Optional[float]) -> ContextManager[None]: .. versionadded:: 4.2 """ if not isinstance(seconds, (int, float, type(None))): - raise TypeError("timeout must be None, an int, or a float") + raise TypeError(f"timeout must be None, an int, or a float, not {type(seconds)}") if seconds and seconds < 0: raise ValueError("timeout cannot be negative") if seconds is not None: diff --git a/pymongo/_asyncio_lock.py b/pymongo/_asyncio_lock.py index 669b0f63a7..a9c409d486 100644 --- a/pymongo/_asyncio_lock.py +++ b/pymongo/_asyncio_lock.py @@ -160,7 +160,7 @@ def release(self) -> None: self._locked = False self._wake_up_first() else: - raise RuntimeError("Lock is not acquired.") + raise RuntimeError("Lock is not acquired") def _wake_up_first(self) -> None: """Ensure that the first waiter will wake up.""" diff --git a/pymongo/_azure_helpers.py b/pymongo/_azure_helpers.py index 704c561cd5..6e86ab5670 100644 --- a/pymongo/_azure_helpers.py +++ b/pymongo/_azure_helpers.py @@ -46,7 +46,7 @@ def _get_azure_response( try: data = json.loads(body) except Exception: - raise ValueError("Azure IMDS response must be in JSON format.") from None + raise ValueError("Azure IMDS response must be in JSON format") from None for key in ["access_token", "expires_in"]: if not data.get(key): diff --git a/pymongo/asynchronous/auth.py b/pymongo/asynchronous/auth.py index b1e6d0125b..8cc4edf19c 100644 --- a/pymongo/asynchronous/auth.py +++ b/pymongo/asynchronous/auth.py @@ -161,7 +161,7 @@ def _password_digest(username: str, password: str) -> str: if len(password) == 0: raise ValueError("password can't be empty") if not isinstance(username, str): - raise TypeError("username must be an instance of str") + raise TypeError(f"username must be an instance of str, not {type(username)}") md5hash = hashlib.md5() # noqa: S324 data = f"{username}:mongo:{password}" diff --git a/pymongo/asynchronous/auth_oidc.py b/pymongo/asynchronous/auth_oidc.py index f1c15045de..38346648c5 100644 --- a/pymongo/asynchronous/auth_oidc.py +++ b/pymongo/asynchronous/auth_oidc.py @@ -213,7 +213,9 @@ def _get_access_token(self) -> Optional[str]: ) resp = cb.fetch(context) if not isinstance(resp, OIDCCallbackResult): - raise ValueError("Callback result must be of type OIDCCallbackResult") + raise ValueError( + f"Callback result must be of type OIDCCallbackResult, not {type(resp)}" + ) self.refresh_token = resp.refresh_token self.access_token = resp.access_token self.token_gen_id += 1 diff --git a/pymongo/asynchronous/client_session.py b/pymongo/asynchronous/client_session.py index d80495d804..4c5171a350 100644 --- a/pymongo/asynchronous/client_session.py +++ b/pymongo/asynchronous/client_session.py @@ -310,7 +310,9 @@ def __init__( ) if max_commit_time_ms is not None: if not isinstance(max_commit_time_ms, int): - raise TypeError("max_commit_time_ms must be an integer or None") + raise TypeError( + f"max_commit_time_ms must be an integer or None, not {type(max_commit_time_ms)}" + ) @property def read_concern(self) -> Optional[ReadConcern]: @@ -902,7 +904,9 @@ def advance_cluster_time(self, cluster_time: Mapping[str, Any]) -> None: another `AsyncClientSession` instance. """ if not isinstance(cluster_time, _Mapping): - raise TypeError("cluster_time must be a subclass of collections.Mapping") + raise TypeError( + f"cluster_time must be a subclass of collections.Mapping, not {type(cluster_time)}" + ) if not isinstance(cluster_time.get("clusterTime"), Timestamp): raise ValueError("Invalid cluster_time") self._advance_cluster_time(cluster_time) @@ -923,7 +927,9 @@ def advance_operation_time(self, operation_time: Timestamp) -> None: another `AsyncClientSession` instance. """ if not isinstance(operation_time, Timestamp): - raise TypeError("operation_time must be an instance of bson.timestamp.Timestamp") + raise TypeError( + f"operation_time must be an instance of bson.timestamp.Timestamp, not {type(operation_time)}" + ) self._advance_operation_time(operation_time) def _process_response(self, reply: Mapping[str, Any]) -> None: diff --git a/pymongo/asynchronous/collection.py b/pymongo/asynchronous/collection.py index 9b73423627..e83a391439 100644 --- a/pymongo/asynchronous/collection.py +++ b/pymongo/asynchronous/collection.py @@ -228,7 +228,7 @@ def __init__( read_concern or database.read_concern, ) if not isinstance(name, str): - raise TypeError("name must be an instance of str") + raise TypeError(f"name must be an instance of str, not {type(name)}") from pymongo.asynchronous.database import AsyncDatabase if not isinstance(database, AsyncDatabase): @@ -2475,7 +2475,7 @@ async def _drop_index( name = helpers_shared._gen_index_name(index_or_name) if not isinstance(name, str): - raise TypeError("index_or_name must be an instance of str or list") + raise TypeError(f"index_or_name must be an instance of str or list, not {type(name)}") cmd = {"dropIndexes": self._name, "index": name} cmd.update(kwargs) @@ -3078,7 +3078,7 @@ async def rename( """ if not isinstance(new_name, str): - raise TypeError("new_name must be an instance of str") + raise TypeError(f"new_name must be an instance of str, not {type(new_name)}") if not new_name or ".." in new_name: raise InvalidName("collection names cannot be empty") @@ -3148,7 +3148,7 @@ async def distinct( """ if not isinstance(key, str): - raise TypeError("key must be an instance of str") + raise TypeError(f"key must be an instance of str, not {type(key)}") cmd = {"distinct": self._name, "key": key} if filter is not None: if "query" in kwargs: @@ -3196,7 +3196,7 @@ async def _find_and_modify( common.validate_is_mapping("filter", filter) if not isinstance(return_document, bool): raise ValueError( - "return_document must be ReturnDocument.BEFORE or ReturnDocument.AFTER" + f"return_document must be ReturnDocument.BEFORE or ReturnDocument.AFTER, not {type(return_document)}" ) collation = validate_collation_or_none(kwargs.pop("collation", None)) cmd = {"findAndModify": self._name, "query": filter, "new": return_document} diff --git a/pymongo/asynchronous/command_cursor.py b/pymongo/asynchronous/command_cursor.py index 5a4559bd77..353c5e91c2 100644 --- a/pymongo/asynchronous/command_cursor.py +++ b/pymongo/asynchronous/command_cursor.py @@ -94,7 +94,9 @@ def __init__( self.batch_size(batch_size) if not isinstance(max_await_time_ms, int) and max_await_time_ms is not None: - raise TypeError("max_await_time_ms must be an integer or None") + raise TypeError( + f"max_await_time_ms must be an integer or None, not {type(max_await_time_ms)}" + ) def __del__(self) -> None: self._die_no_lock() @@ -115,7 +117,7 @@ def batch_size(self, batch_size: int) -> AsyncCommandCursor[_DocumentType]: :param batch_size: The size of each batch of results requested. """ if not isinstance(batch_size, int): - raise TypeError("batch_size must be an integer") + raise TypeError(f"batch_size must be an integer, not {type(batch_size)}") if batch_size < 0: raise ValueError("batch_size must be >= 0") diff --git a/pymongo/asynchronous/cursor.py b/pymongo/asynchronous/cursor.py index 8193e53282..9101197ce2 100644 --- a/pymongo/asynchronous/cursor.py +++ b/pymongo/asynchronous/cursor.py @@ -146,9 +146,9 @@ def __init__( spec: Mapping[str, Any] = filter or {} validate_is_mapping("filter", spec) if not isinstance(skip, int): - raise TypeError("skip must be an instance of int") + raise TypeError(f"skip must be an instance of int, not {type(skip)}") if not isinstance(limit, int): - raise TypeError("limit must be an instance of int") + raise TypeError(f"limit must be an instance of int, not {type(limit)}") validate_boolean("no_cursor_timeout", no_cursor_timeout) if no_cursor_timeout and not self._explicit_session: warnings.warn( @@ -171,7 +171,7 @@ def __init__( validate_boolean("allow_partial_results", allow_partial_results) validate_boolean("oplog_replay", oplog_replay) if not isinstance(batch_size, int): - raise TypeError("batch_size must be an integer") + raise TypeError(f"batch_size must be an integer, not {type(batch_size)}") if batch_size < 0: raise ValueError("batch_size must be >= 0") # Only set if allow_disk_use is provided by the user, else None. @@ -388,7 +388,7 @@ async def add_option(self, mask: int) -> AsyncCursor[_DocumentType]: cursor.add_option(2) """ if not isinstance(mask, int): - raise TypeError("mask must be an int") + raise TypeError(f"mask must be an int, not {type(mask)}") self._check_okay_to_chain() if mask & _QUERY_OPTIONS["exhaust"]: @@ -408,7 +408,7 @@ def remove_option(self, mask: int) -> AsyncCursor[_DocumentType]: cursor.remove_option(2) """ if not isinstance(mask, int): - raise TypeError("mask must be an int") + raise TypeError(f"mask must be an int, not {type(mask)}") self._check_okay_to_chain() if mask & _QUERY_OPTIONS["exhaust"]: @@ -432,7 +432,7 @@ def allow_disk_use(self, allow_disk_use: bool) -> AsyncCursor[_DocumentType]: .. versionadded:: 3.11 """ if not isinstance(allow_disk_use, bool): - raise TypeError("allow_disk_use must be a bool") + raise TypeError(f"allow_disk_use must be a bool, not {type(allow_disk_use)}") self._check_okay_to_chain() self._allow_disk_use = allow_disk_use @@ -451,7 +451,7 @@ def limit(self, limit: int) -> AsyncCursor[_DocumentType]: .. seealso:: The MongoDB documentation on `limit `_. """ if not isinstance(limit, int): - raise TypeError("limit must be an integer") + raise TypeError(f"limit must be an integer, not {type(limit)}") if self._exhaust: raise InvalidOperation("Can't use limit and exhaust together.") self._check_okay_to_chain() @@ -479,7 +479,7 @@ def batch_size(self, batch_size: int) -> AsyncCursor[_DocumentType]: :param batch_size: The size of each batch of results requested. """ if not isinstance(batch_size, int): - raise TypeError("batch_size must be an integer") + raise TypeError(f"batch_size must be an integer, not {type(batch_size)}") if batch_size < 0: raise ValueError("batch_size must be >= 0") self._check_okay_to_chain() @@ -499,7 +499,7 @@ def skip(self, skip: int) -> AsyncCursor[_DocumentType]: :param skip: the number of results to skip """ if not isinstance(skip, int): - raise TypeError("skip must be an integer") + raise TypeError(f"skip must be an integer, not {type(skip)}") if skip < 0: raise ValueError("skip must be >= 0") self._check_okay_to_chain() @@ -520,7 +520,7 @@ def max_time_ms(self, max_time_ms: Optional[int]) -> AsyncCursor[_DocumentType]: :param max_time_ms: the time limit after which the operation is aborted """ if not isinstance(max_time_ms, int) and max_time_ms is not None: - raise TypeError("max_time_ms must be an integer or None") + raise TypeError(f"max_time_ms must be an integer or None, not {type(max_time_ms)}") self._check_okay_to_chain() self._max_time_ms = max_time_ms @@ -543,7 +543,9 @@ def max_await_time_ms(self, max_await_time_ms: Optional[int]) -> AsyncCursor[_Do .. versionadded:: 3.2 """ if not isinstance(max_await_time_ms, int) and max_await_time_ms is not None: - raise TypeError("max_await_time_ms must be an integer or None") + raise TypeError( + f"max_await_time_ms must be an integer or None, not {type(max_await_time_ms)}" + ) self._check_okay_to_chain() # Ignore max_await_time_ms if not tailable or await_data is False. @@ -679,7 +681,7 @@ def max(self, spec: _Sort) -> AsyncCursor[_DocumentType]: .. versionadded:: 2.7 """ if not isinstance(spec, (list, tuple)): - raise TypeError("spec must be an instance of list or tuple") + raise TypeError(f"spec must be an instance of list or tuple, not {type(spec)}") self._check_okay_to_chain() self._max = dict(spec) @@ -701,7 +703,7 @@ def min(self, spec: _Sort) -> AsyncCursor[_DocumentType]: .. versionadded:: 2.7 """ if not isinstance(spec, (list, tuple)): - raise TypeError("spec must be an instance of list or tuple") + raise TypeError(f"spec must be an instance of list or tuple, not {type(spec)}") self._check_okay_to_chain() self._min = dict(spec) diff --git a/pymongo/asynchronous/database.py b/pymongo/asynchronous/database.py index 98a0a6ff3b..4aba9ab0e9 100644 --- a/pymongo/asynchronous/database.py +++ b/pymongo/asynchronous/database.py @@ -122,7 +122,7 @@ def __init__( from pymongo.asynchronous.mongo_client import AsyncMongoClient if not isinstance(name, str): - raise TypeError("name must be an instance of str") + raise TypeError(f"name must be an instance of str, not {type(name)}") if not isinstance(client, AsyncMongoClient): # This is for compatibility with mocked and subclassed types, such as in Motor. @@ -1310,7 +1310,7 @@ async def drop_collection( name = name.name if not isinstance(name, str): - raise TypeError("name_or_collection must be an instance of str") + raise TypeError(f"name_or_collection must be an instance of str, not {type(name)}") encrypted_fields = await self._get_encrypted_fields( {"encryptedFields": encrypted_fields}, name, @@ -1374,7 +1374,9 @@ async def validate_collection( name = name.name if not isinstance(name, str): - raise TypeError("name_or_collection must be an instance of str or AsyncCollection") + raise TypeError( + f"name_or_collection must be an instance of str or AsyncCollection, not {type(name)}" + ) cmd = {"validate": name, "scandata": scandata, "full": full} if comment is not None: cmd["comment"] = comment diff --git a/pymongo/asynchronous/encryption.py b/pymongo/asynchronous/encryption.py index 98ab68527c..f777104cf5 100644 --- a/pymongo/asynchronous/encryption.py +++ b/pymongo/asynchronous/encryption.py @@ -322,7 +322,9 @@ async def insert_data_key(self, data_key: bytes) -> Binary: raw_doc = RawBSONDocument(data_key, _KEY_VAULT_OPTS) data_key_id = raw_doc.get("_id") if not isinstance(data_key_id, Binary) or data_key_id.subtype != UUID_SUBTYPE: - raise TypeError("data_key _id must be Binary with a UUID subtype") + raise TypeError( + f"data_key _id must be Binary with a UUID subtype, not {type(data_key_id)}" + ) assert self.key_vault_coll is not None await self.key_vault_coll.insert_one(raw_doc) @@ -644,7 +646,9 @@ def __init__( ) if not isinstance(codec_options, CodecOptions): - raise TypeError("codec_options must be an instance of bson.codec_options.CodecOptions") + raise TypeError( + f"codec_options must be an instance of bson.codec_options.CodecOptions, not {type(codec_options)}" + ) if not isinstance(key_vault_client, AsyncMongoClient): # This is for compatibility with mocked and subclassed types, such as in Motor. diff --git a/pymongo/asynchronous/mongo_client.py b/pymongo/asynchronous/mongo_client.py index 1600e50628..cf7de19c2f 100644 --- a/pymongo/asynchronous/mongo_client.py +++ b/pymongo/asynchronous/mongo_client.py @@ -750,7 +750,7 @@ def __init__( if port is None: port = self.PORT if not isinstance(port, int): - raise TypeError("port must be an instance of int") + raise TypeError(f"port must be an instance of int, not {type(port)}") # _pool_class, _monitor_class, and _condition_class are for deep # customization of PyMongo, e.g. Motor. @@ -1971,7 +1971,7 @@ async def _close_cursor_now( The cursor is closed synchronously on the current thread. """ if not isinstance(cursor_id, int): - raise TypeError("cursor_id must be an instance of int") + raise TypeError(f"cursor_id must be an instance of int, not {type(cursor_id)}") try: if conn_mgr: @@ -2093,7 +2093,9 @@ async def _tmp_session( """If provided session is None, lend a temporary session.""" if session is not None: if not isinstance(session, client_session.AsyncClientSession): - raise ValueError("'session' argument must be an AsyncClientSession or None.") + raise ValueError( + f"'session' argument must be an AsyncClientSession or None, not {type(session)}" + ) # Don't call end_session. yield session return @@ -2247,7 +2249,9 @@ async def drop_database( name = name.name if not isinstance(name, str): - raise TypeError("name_or_database must be an instance of str or a AsyncDatabase") + raise TypeError( + f"name_or_database must be an instance of str or a AsyncDatabase, not {type(name)}" + ) async with await self._conn_for_writes(session, operation=_Op.DROP_DATABASE) as conn: await self[name]._command( diff --git a/pymongo/auth_shared.py b/pymongo/auth_shared.py index 9534bd74ad..410521d73a 100644 --- a/pymongo/auth_shared.py +++ b/pymongo/auth_shared.py @@ -107,7 +107,7 @@ def _build_credentials_tuple( ) -> MongoCredential: """Build and return a mechanism specific credentials tuple.""" if mech not in ("MONGODB-X509", "MONGODB-AWS", "MONGODB-OIDC") and user is None: - raise ConfigurationError(f"{mech} requires a username.") + raise ConfigurationError(f"{mech} requires a username") if mech == "GSSAPI": if source is not None and source != "$external": raise ValueError("authentication source must be $external or None for GSSAPI") @@ -219,7 +219,7 @@ def _build_credentials_tuple( else: source_database = source or database or "admin" if passwd is None: - raise ConfigurationError("A password is required.") + raise ConfigurationError("A password is required") return MongoCredential(mech, source_database, user, passwd, None, _Cache()) diff --git a/pymongo/collation.py b/pymongo/collation.py index 9adcb2e408..fc84b937f2 100644 --- a/pymongo/collation.py +++ b/pymongo/collation.py @@ -223,4 +223,4 @@ def validate_collation_or_none( return value.document if isinstance(value, dict): return value - raise TypeError("collation must be a dict, an instance of collation.Collation, or None.") + raise TypeError("collation must be a dict, an instance of collation.Collation, or None") diff --git a/pymongo/common.py b/pymongo/common.py index b442da6a3e..4be7a3122a 100644 --- a/pymongo/common.py +++ b/pymongo/common.py @@ -202,7 +202,7 @@ def validate_integer(option: str, value: Any) -> int: return int(value) except ValueError: raise ValueError(f"The value of {option} must be an integer") from None - raise TypeError(f"Wrong type for {option}, value must be an integer") + raise TypeError(f"Wrong type for {option}, value must be an integer, not {type(value)}") def validate_positive_integer(option: str, value: Any) -> int: @@ -250,7 +250,7 @@ def validate_string(option: str, value: Any) -> str: """Validates that 'value' is an instance of `str`.""" if isinstance(value, str): return value - raise TypeError(f"Wrong type for {option}, value must be an instance of str") + raise TypeError(f"Wrong type for {option}, value must be an instance of str, not {type(value)}") def validate_string_or_none(option: str, value: Any) -> Optional[str]: @@ -269,7 +269,9 @@ def validate_int_or_basestring(option: str, value: Any) -> Union[int, str]: return int(value) except ValueError: return value - raise TypeError(f"Wrong type for {option}, value must be an integer or a string") + raise TypeError( + f"Wrong type for {option}, value must be an integer or a string, not {type(value)}" + ) def validate_non_negative_int_or_basestring(option: Any, value: Any) -> Union[int, str]: @@ -282,7 +284,9 @@ def validate_non_negative_int_or_basestring(option: Any, value: Any) -> Union[in except ValueError: return value return validate_non_negative_integer(option, val) - raise TypeError(f"Wrong type for {option}, value must be an non negative integer or a string") + raise TypeError( + f"Wrong type for {option}, value must be an non negative integer or a string, not {type(value)}" + ) def validate_positive_float(option: str, value: Any) -> float: @@ -365,7 +369,7 @@ def validate_max_staleness(option: str, value: Any) -> int: def validate_read_preference(dummy: Any, value: Any) -> _ServerMode: """Validate a read preference.""" if not isinstance(value, _ServerMode): - raise TypeError(f"{value!r} is not a read preference.") + raise TypeError(f"{value!r} is not a read preference") return value @@ -441,7 +445,9 @@ def validate_auth_mechanism_properties(option: str, value: Any) -> dict[str, Uni props: dict[str, Any] = {} if not isinstance(value, str): if not isinstance(value, dict): - raise ValueError("Auth mechanism properties must be given as a string or a dictionary") + raise ValueError( + f"Auth mechanism properties must be given as a string or a dictionary, not {type(value)}" + ) for key, value in value.items(): # noqa: B020 if isinstance(value, str): props[key] = value @@ -453,7 +459,7 @@ def validate_auth_mechanism_properties(option: str, value: Any) -> dict[str, Uni from pymongo.auth_oidc_shared import OIDCCallback if not isinstance(value, OIDCCallback): - raise ValueError("callback must be an OIDCCallback object") + raise ValueError(f"callback must be an OIDCCallback object, not {type(value)}") props[key] = value else: raise ValueError(f"Invalid type for auth mechanism property {key}, {type(value)}") @@ -476,7 +482,7 @@ def validate_auth_mechanism_properties(option: str, value: Any) -> dict[str, Uni raise ValueError( f"{key} is not a supported auth " "mechanism property. Must be one of " - f"{tuple(_MECHANISM_PROPS)}." + f"{tuple(_MECHANISM_PROPS)}" ) if key == "CANONICALIZE_HOST_NAME": @@ -520,7 +526,7 @@ def validate_type_registry(option: Any, value: Any) -> Optional[TypeRegistry]: def validate_list(option: str, value: Any) -> list: """Validates that 'value' is a list.""" if not isinstance(value, list): - raise TypeError(f"{option} must be a list") + raise TypeError(f"{option} must be a list, not {type(value)}") return value @@ -587,7 +593,7 @@ def validate_server_api_or_none(option: Any, value: Any) -> Optional[ServerApi]: if value is None: return value if not isinstance(value, ServerApi): - raise TypeError(f"{option} must be an instance of ServerApi") + raise TypeError(f"{option} must be an instance of ServerApi, not {type(value)}") return value @@ -596,7 +602,7 @@ def validate_is_callable_or_none(option: Any, value: Any) -> Optional[Callable]: if value is None: return value if not callable(value): - raise ValueError(f"{option} must be a callable") + raise ValueError(f"{option} must be a callable, not {type(value)}") return value @@ -651,7 +657,7 @@ def validate_auto_encryption_opts_or_none(option: Any, value: Any) -> Optional[A from pymongo.encryption_options import AutoEncryptionOpts if not isinstance(value, AutoEncryptionOpts): - raise TypeError(f"{option} must be an instance of AutoEncryptionOpts") + raise TypeError(f"{option} must be an instance of AutoEncryptionOpts, not {type(value)}") return value @@ -668,7 +674,9 @@ def validate_datetime_conversion(option: Any, value: Any) -> Optional[DatetimeCo elif isinstance(value, int): return DatetimeConversion(value) - raise TypeError(f"{option} must be a str or int representing DatetimeConversion") + raise TypeError( + f"{option} must be a str or int representing DatetimeConversion, not {type(value)}" + ) def validate_server_monitoring_mode(option: str, value: str) -> str: @@ -928,12 +936,14 @@ def __init__( if not isinstance(write_concern, WriteConcern): raise TypeError( - "write_concern must be an instance of pymongo.write_concern.WriteConcern" + f"write_concern must be an instance of pymongo.write_concern.WriteConcern, not {type(write_concern)}" ) self._write_concern = write_concern if not isinstance(read_concern, ReadConcern): - raise TypeError("read_concern must be an instance of pymongo.read_concern.ReadConcern") + raise TypeError( + f"read_concern must be an instance of pymongo.read_concern.ReadConcern, not {type(read_concern)}" + ) self._read_concern = read_concern @property diff --git a/pymongo/compression_support.py b/pymongo/compression_support.py index f49b56cc96..7486451730 100644 --- a/pymongo/compression_support.py +++ b/pymongo/compression_support.py @@ -91,7 +91,7 @@ def validate_zlib_compression_level(option: str, value: Any) -> int: try: level = int(value) except Exception: - raise TypeError(f"{option} must be an integer, not {value!r}.") from None + raise TypeError(f"{option} must be an integer, not {value!r}") from None if level < -1 or level > 9: raise ValueError("%s must be between -1 and 9, not %d." % (option, level)) return level diff --git a/pymongo/driver_info.py b/pymongo/driver_info.py index 5ca3f952cd..724a6f20d5 100644 --- a/pymongo/driver_info.py +++ b/pymongo/driver_info.py @@ -39,7 +39,7 @@ def __new__( for key, value in self._asdict().items(): if value is not None and not isinstance(value, str): raise TypeError( - f"Wrong type for DriverInfo {key} option, value must be an instance of str" + f"Wrong type for DriverInfo {key} option, value must be an instance of str, not {type(value)}" ) return self diff --git a/pymongo/encryption_options.py b/pymongo/encryption_options.py index ee749e7ac1..26dfbf5f03 100644 --- a/pymongo/encryption_options.py +++ b/pymongo/encryption_options.py @@ -225,7 +225,9 @@ def __init__( mongocryptd_spawn_args = ["--idleShutdownTimeoutSecs=60"] self._mongocryptd_spawn_args = mongocryptd_spawn_args if not isinstance(self._mongocryptd_spawn_args, list): - raise TypeError("mongocryptd_spawn_args must be a list") + raise TypeError( + f"mongocryptd_spawn_args must be a list, not {type(self._mongocryptd_spawn_args)}" + ) if not any("idleShutdownTimeoutSecs" in s for s in self._mongocryptd_spawn_args): self._mongocryptd_spawn_args.append("--idleShutdownTimeoutSecs=60") # Maps KMS provider name to a SSLContext. diff --git a/pymongo/helpers_shared.py b/pymongo/helpers_shared.py index 83ea2ddf78..c6b820c1c2 100644 --- a/pymongo/helpers_shared.py +++ b/pymongo/helpers_shared.py @@ -122,7 +122,7 @@ def _index_list( """ if direction is not None: if not isinstance(key_or_list, str): - raise TypeError("Expected a string and a direction") + raise TypeError(f"Expected a string and a direction, not {type(key_or_list)}") return [(key_or_list, direction)] else: if isinstance(key_or_list, str): @@ -132,7 +132,9 @@ def _index_list( elif isinstance(key_or_list, abc.Mapping): return list(key_or_list.items()) elif not isinstance(key_or_list, (list, tuple)): - raise TypeError("if no direction is specified, key_or_list must be an instance of list") + raise TypeError( + f"if no direction is specified, key_or_list must be an instance of list, not {type(key_or_list)}" + ) values: list[tuple[str, int]] = [] for item in key_or_list: if isinstance(item, str): @@ -172,11 +174,12 @@ def _index_document(index_list: _IndexList) -> dict[str, Any]: def _validate_index_key_pair(key: Any, value: Any) -> None: if not isinstance(key, str): - raise TypeError("first item in each key pair must be an instance of str") + raise TypeError(f"first item in each key pair must be an instance of str, not {type(key)}") if not isinstance(value, (str, int, abc.Mapping)): raise TypeError( "second item in each key pair must be 1, -1, " "'2d', or another valid MongoDB index specifier." + f", not {type(value)}" ) diff --git a/pymongo/monitoring.py b/pymongo/monitoring.py index 96f88597d2..38d6e3a22a 100644 --- a/pymongo/monitoring.py +++ b/pymongo/monitoring.py @@ -472,14 +472,15 @@ def _validate_event_listeners( ) -> Sequence[_EventListeners]: """Validate event listeners""" if not isinstance(listeners, abc.Sequence): - raise TypeError(f"{option} must be a list or tuple") + raise TypeError(f"{option} must be a list or tuple, not {type(listeners)}") for listener in listeners: if not isinstance(listener, _EventListener): raise TypeError( f"Listeners for {option} must be either a " "CommandListener, ServerHeartbeatListener, " "ServerListener, TopologyListener, or " - "ConnectionPoolListener." + "ConnectionPoolListener," + f"not {type(listener)}" ) return listeners @@ -496,7 +497,8 @@ def register(listener: _EventListener) -> None: f"Listeners for {listener} must be either a " "CommandListener, ServerHeartbeatListener, " "ServerListener, TopologyListener, or " - "ConnectionPoolListener." + "ConnectionPoolListener," + f"not {type(listener)}" ) if isinstance(listener, CommandListener): _LISTENERS.command_listeners.append(listener) diff --git a/pymongo/read_concern.py b/pymongo/read_concern.py index fa2f4a318a..17f3a46edb 100644 --- a/pymongo/read_concern.py +++ b/pymongo/read_concern.py @@ -38,7 +38,7 @@ def __init__(self, level: Optional[str] = None) -> None: if level is None or isinstance(level, str): self.__level = level else: - raise TypeError("level must be a string or None.") + raise TypeError(f"level must be a string or None, not {type(level)}") @property def level(self) -> Optional[str]: diff --git a/pymongo/ssl_support.py b/pymongo/ssl_support.py index 580d71f9b0..0faf21ba8f 100644 --- a/pymongo/ssl_support.py +++ b/pymongo/ssl_support.py @@ -115,4 +115,4 @@ class SSLError(Exception): # type: ignore def get_ssl_context(*dummy): # type: ignore """No ssl module, raise ConfigurationError.""" - raise ConfigurationError("The ssl module is not available.") + raise ConfigurationError("The ssl module is not available") diff --git a/pymongo/synchronous/auth.py b/pymongo/synchronous/auth.py index 56860eff3b..6041ebdbe3 100644 --- a/pymongo/synchronous/auth.py +++ b/pymongo/synchronous/auth.py @@ -158,7 +158,7 @@ def _password_digest(username: str, password: str) -> str: if len(password) == 0: raise ValueError("password can't be empty") if not isinstance(username, str): - raise TypeError("username must be an instance of str") + raise TypeError(f"username must be an instance of str, not {type(username)}") md5hash = hashlib.md5() # noqa: S324 data = f"{username}:mongo:{password}" diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index 5a8967d96b..c5efdd5fcc 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -213,7 +213,9 @@ def _get_access_token(self) -> Optional[str]: ) resp = cb.fetch(context) if not isinstance(resp, OIDCCallbackResult): - raise ValueError("Callback result must be of type OIDCCallbackResult") + raise ValueError( + f"Callback result must be of type OIDCCallbackResult, not {type(resp)}" + ) self.refresh_token = resp.refresh_token self.access_token = resp.access_token self.token_gen_id += 1 diff --git a/pymongo/synchronous/client_session.py b/pymongo/synchronous/client_session.py index f1d680fc0a..298dd7b357 100644 --- a/pymongo/synchronous/client_session.py +++ b/pymongo/synchronous/client_session.py @@ -309,7 +309,9 @@ def __init__( ) if max_commit_time_ms is not None: if not isinstance(max_commit_time_ms, int): - raise TypeError("max_commit_time_ms must be an integer or None") + raise TypeError( + f"max_commit_time_ms must be an integer or None, not {type(max_commit_time_ms)}" + ) @property def read_concern(self) -> Optional[ReadConcern]: @@ -897,7 +899,9 @@ def advance_cluster_time(self, cluster_time: Mapping[str, Any]) -> None: another `ClientSession` instance. """ if not isinstance(cluster_time, _Mapping): - raise TypeError("cluster_time must be a subclass of collections.Mapping") + raise TypeError( + f"cluster_time must be a subclass of collections.Mapping, not {type(cluster_time)}" + ) if not isinstance(cluster_time.get("clusterTime"), Timestamp): raise ValueError("Invalid cluster_time") self._advance_cluster_time(cluster_time) @@ -918,7 +922,9 @@ def advance_operation_time(self, operation_time: Timestamp) -> None: another `ClientSession` instance. """ if not isinstance(operation_time, Timestamp): - raise TypeError("operation_time must be an instance of bson.timestamp.Timestamp") + raise TypeError( + f"operation_time must be an instance of bson.timestamp.Timestamp, not {type(operation_time)}" + ) self._advance_operation_time(operation_time) def _process_response(self, reply: Mapping[str, Any]) -> None: diff --git a/pymongo/synchronous/collection.py b/pymongo/synchronous/collection.py index 6edfddc9a9..b956ac58a5 100644 --- a/pymongo/synchronous/collection.py +++ b/pymongo/synchronous/collection.py @@ -231,7 +231,7 @@ def __init__( read_concern or database.read_concern, ) if not isinstance(name, str): - raise TypeError("name must be an instance of str") + raise TypeError(f"name must be an instance of str, not {type(name)}") from pymongo.synchronous.database import Database if not isinstance(database, Database): @@ -2472,7 +2472,7 @@ def _drop_index( name = helpers_shared._gen_index_name(index_or_name) if not isinstance(name, str): - raise TypeError("index_or_name must be an instance of str or list") + raise TypeError(f"index_or_name must be an instance of str or list, not {type(name)}") cmd = {"dropIndexes": self._name, "index": name} cmd.update(kwargs) @@ -3071,7 +3071,7 @@ def rename( """ if not isinstance(new_name, str): - raise TypeError("new_name must be an instance of str") + raise TypeError(f"new_name must be an instance of str, not {type(new_name)}") if not new_name or ".." in new_name: raise InvalidName("collection names cannot be empty") @@ -3141,7 +3141,7 @@ def distinct( """ if not isinstance(key, str): - raise TypeError("key must be an instance of str") + raise TypeError(f"key must be an instance of str, not {type(key)}") cmd = {"distinct": self._name, "key": key} if filter is not None: if "query" in kwargs: @@ -3189,7 +3189,7 @@ def _find_and_modify( common.validate_is_mapping("filter", filter) if not isinstance(return_document, bool): raise ValueError( - "return_document must be ReturnDocument.BEFORE or ReturnDocument.AFTER" + f"return_document must be ReturnDocument.BEFORE or ReturnDocument.AFTER, not {type(return_document)}" ) collation = validate_collation_or_none(kwargs.pop("collation", None)) cmd = {"findAndModify": self._name, "query": filter, "new": return_document} diff --git a/pymongo/synchronous/command_cursor.py b/pymongo/synchronous/command_cursor.py index 3a4372856a..e23519d740 100644 --- a/pymongo/synchronous/command_cursor.py +++ b/pymongo/synchronous/command_cursor.py @@ -94,7 +94,9 @@ def __init__( self.batch_size(batch_size) if not isinstance(max_await_time_ms, int) and max_await_time_ms is not None: - raise TypeError("max_await_time_ms must be an integer or None") + raise TypeError( + f"max_await_time_ms must be an integer or None, not {type(max_await_time_ms)}" + ) def __del__(self) -> None: self._die_no_lock() @@ -115,7 +117,7 @@ def batch_size(self, batch_size: int) -> CommandCursor[_DocumentType]: :param batch_size: The size of each batch of results requested. """ if not isinstance(batch_size, int): - raise TypeError("batch_size must be an integer") + raise TypeError(f"batch_size must be an integer, not {type(batch_size)}") if batch_size < 0: raise ValueError("batch_size must be >= 0") diff --git a/pymongo/synchronous/cursor.py b/pymongo/synchronous/cursor.py index b35098a327..cda093ee19 100644 --- a/pymongo/synchronous/cursor.py +++ b/pymongo/synchronous/cursor.py @@ -146,9 +146,9 @@ def __init__( spec: Mapping[str, Any] = filter or {} validate_is_mapping("filter", spec) if not isinstance(skip, int): - raise TypeError("skip must be an instance of int") + raise TypeError(f"skip must be an instance of int, not {type(skip)}") if not isinstance(limit, int): - raise TypeError("limit must be an instance of int") + raise TypeError(f"limit must be an instance of int, not {type(limit)}") validate_boolean("no_cursor_timeout", no_cursor_timeout) if no_cursor_timeout and not self._explicit_session: warnings.warn( @@ -171,7 +171,7 @@ def __init__( validate_boolean("allow_partial_results", allow_partial_results) validate_boolean("oplog_replay", oplog_replay) if not isinstance(batch_size, int): - raise TypeError("batch_size must be an integer") + raise TypeError(f"batch_size must be an integer, not {type(batch_size)}") if batch_size < 0: raise ValueError("batch_size must be >= 0") # Only set if allow_disk_use is provided by the user, else None. @@ -388,7 +388,7 @@ def add_option(self, mask: int) -> Cursor[_DocumentType]: cursor.add_option(2) """ if not isinstance(mask, int): - raise TypeError("mask must be an int") + raise TypeError(f"mask must be an int, not {type(mask)}") self._check_okay_to_chain() if mask & _QUERY_OPTIONS["exhaust"]: @@ -408,7 +408,7 @@ def remove_option(self, mask: int) -> Cursor[_DocumentType]: cursor.remove_option(2) """ if not isinstance(mask, int): - raise TypeError("mask must be an int") + raise TypeError(f"mask must be an int, not {type(mask)}") self._check_okay_to_chain() if mask & _QUERY_OPTIONS["exhaust"]: @@ -432,7 +432,7 @@ def allow_disk_use(self, allow_disk_use: bool) -> Cursor[_DocumentType]: .. versionadded:: 3.11 """ if not isinstance(allow_disk_use, bool): - raise TypeError("allow_disk_use must be a bool") + raise TypeError(f"allow_disk_use must be a bool, not {type(allow_disk_use)}") self._check_okay_to_chain() self._allow_disk_use = allow_disk_use @@ -451,7 +451,7 @@ def limit(self, limit: int) -> Cursor[_DocumentType]: .. seealso:: The MongoDB documentation on `limit `_. """ if not isinstance(limit, int): - raise TypeError("limit must be an integer") + raise TypeError(f"limit must be an integer, not {type(limit)}") if self._exhaust: raise InvalidOperation("Can't use limit and exhaust together.") self._check_okay_to_chain() @@ -479,7 +479,7 @@ def batch_size(self, batch_size: int) -> Cursor[_DocumentType]: :param batch_size: The size of each batch of results requested. """ if not isinstance(batch_size, int): - raise TypeError("batch_size must be an integer") + raise TypeError(f"batch_size must be an integer, not {type(batch_size)}") if batch_size < 0: raise ValueError("batch_size must be >= 0") self._check_okay_to_chain() @@ -499,7 +499,7 @@ def skip(self, skip: int) -> Cursor[_DocumentType]: :param skip: the number of results to skip """ if not isinstance(skip, int): - raise TypeError("skip must be an integer") + raise TypeError(f"skip must be an integer, not {type(skip)}") if skip < 0: raise ValueError("skip must be >= 0") self._check_okay_to_chain() @@ -520,7 +520,7 @@ def max_time_ms(self, max_time_ms: Optional[int]) -> Cursor[_DocumentType]: :param max_time_ms: the time limit after which the operation is aborted """ if not isinstance(max_time_ms, int) and max_time_ms is not None: - raise TypeError("max_time_ms must be an integer or None") + raise TypeError(f"max_time_ms must be an integer or None, not {type(max_time_ms)}") self._check_okay_to_chain() self._max_time_ms = max_time_ms @@ -543,7 +543,9 @@ def max_await_time_ms(self, max_await_time_ms: Optional[int]) -> Cursor[_Documen .. versionadded:: 3.2 """ if not isinstance(max_await_time_ms, int) and max_await_time_ms is not None: - raise TypeError("max_await_time_ms must be an integer or None") + raise TypeError( + f"max_await_time_ms must be an integer or None, not {type(max_await_time_ms)}" + ) self._check_okay_to_chain() # Ignore max_await_time_ms if not tailable or await_data is False. @@ -677,7 +679,7 @@ def max(self, spec: _Sort) -> Cursor[_DocumentType]: .. versionadded:: 2.7 """ if not isinstance(spec, (list, tuple)): - raise TypeError("spec must be an instance of list or tuple") + raise TypeError(f"spec must be an instance of list or tuple, not {type(spec)}") self._check_okay_to_chain() self._max = dict(spec) @@ -699,7 +701,7 @@ def min(self, spec: _Sort) -> Cursor[_DocumentType]: .. versionadded:: 2.7 """ if not isinstance(spec, (list, tuple)): - raise TypeError("spec must be an instance of list or tuple") + raise TypeError(f"spec must be an instance of list or tuple, not {type(spec)}") self._check_okay_to_chain() self._min = dict(spec) diff --git a/pymongo/synchronous/database.py b/pymongo/synchronous/database.py index a0bef55343..0dc03cb746 100644 --- a/pymongo/synchronous/database.py +++ b/pymongo/synchronous/database.py @@ -122,7 +122,7 @@ def __init__( from pymongo.synchronous.mongo_client import MongoClient if not isinstance(name, str): - raise TypeError("name must be an instance of str") + raise TypeError(f"name must be an instance of str, not {type(name)}") if not isinstance(client, MongoClient): # This is for compatibility with mocked and subclassed types, such as in Motor. @@ -1303,7 +1303,7 @@ def drop_collection( name = name.name if not isinstance(name, str): - raise TypeError("name_or_collection must be an instance of str") + raise TypeError(f"name_or_collection must be an instance of str, not {type(name)}") encrypted_fields = self._get_encrypted_fields( {"encryptedFields": encrypted_fields}, name, @@ -1367,7 +1367,9 @@ def validate_collection( name = name.name if not isinstance(name, str): - raise TypeError("name_or_collection must be an instance of str or Collection") + raise TypeError( + f"name_or_collection must be an instance of str or Collection, not {type(name)}" + ) cmd = {"validate": name, "scandata": scandata, "full": full} if comment is not None: cmd["comment"] = comment diff --git a/pymongo/synchronous/encryption.py b/pymongo/synchronous/encryption.py index d41169861f..59f38e1913 100644 --- a/pymongo/synchronous/encryption.py +++ b/pymongo/synchronous/encryption.py @@ -320,7 +320,9 @@ def insert_data_key(self, data_key: bytes) -> Binary: raw_doc = RawBSONDocument(data_key, _KEY_VAULT_OPTS) data_key_id = raw_doc.get("_id") if not isinstance(data_key_id, Binary) or data_key_id.subtype != UUID_SUBTYPE: - raise TypeError("data_key _id must be Binary with a UUID subtype") + raise TypeError( + f"data_key _id must be Binary with a UUID subtype, not {type(data_key_id)}" + ) assert self.key_vault_coll is not None self.key_vault_coll.insert_one(raw_doc) @@ -642,7 +644,9 @@ def __init__( ) if not isinstance(codec_options, CodecOptions): - raise TypeError("codec_options must be an instance of bson.codec_options.CodecOptions") + raise TypeError( + f"codec_options must be an instance of bson.codec_options.CodecOptions, not {type(codec_options)}" + ) if not isinstance(key_vault_client, MongoClient): # This is for compatibility with mocked and subclassed types, such as in Motor. diff --git a/pymongo/synchronous/mongo_client.py b/pymongo/synchronous/mongo_client.py index a694a58c1e..706623c214 100644 --- a/pymongo/synchronous/mongo_client.py +++ b/pymongo/synchronous/mongo_client.py @@ -748,7 +748,7 @@ def __init__( if port is None: port = self.PORT if not isinstance(port, int): - raise TypeError("port must be an instance of int") + raise TypeError(f"port must be an instance of int, not {type(port)}") # _pool_class, _monitor_class, and _condition_class are for deep # customization of PyMongo, e.g. Motor. @@ -1965,7 +1965,7 @@ def _close_cursor_now( The cursor is closed synchronously on the current thread. """ if not isinstance(cursor_id, int): - raise TypeError("cursor_id must be an instance of int") + raise TypeError(f"cursor_id must be an instance of int, not {type(cursor_id)}") try: if conn_mgr: @@ -2087,7 +2087,9 @@ def _tmp_session( """If provided session is None, lend a temporary session.""" if session is not None: if not isinstance(session, client_session.ClientSession): - raise ValueError("'session' argument must be a ClientSession or None.") + raise ValueError( + f"'session' argument must be a ClientSession or None, not {type(session)}" + ) # Don't call end_session. yield session return @@ -2235,7 +2237,9 @@ def drop_database( name = name.name if not isinstance(name, str): - raise TypeError("name_or_database must be an instance of str or a Database") + raise TypeError( + f"name_or_database must be an instance of str or a Database, not {type(name)}" + ) with self._conn_for_writes(session, operation=_Op.DROP_DATABASE) as conn: self[name]._command( diff --git a/pymongo/uri_parser.py b/pymongo/uri_parser.py index 7018dad7d8..8f56ae4093 100644 --- a/pymongo/uri_parser.py +++ b/pymongo/uri_parser.py @@ -91,7 +91,7 @@ def parse_userinfo(userinfo: str) -> tuple[str, str]: user, _, passwd = userinfo.partition(":") # No password is expected with GSSAPI authentication. if not user: - raise InvalidURI("The empty string is not valid username.") + raise InvalidURI("The empty string is not valid username") return unquote_plus(user), unquote_plus(passwd) @@ -347,7 +347,7 @@ def split_options( semi_idx = opts.find(";") try: if and_idx >= 0 and semi_idx >= 0: - raise InvalidURI("Can not mix '&' and ';' for option separators.") + raise InvalidURI("Can not mix '&' and ';' for option separators") elif and_idx >= 0: options = _parse_options(opts, "&") elif semi_idx >= 0: @@ -357,7 +357,7 @@ def split_options( else: raise ValueError except ValueError: - raise InvalidURI("MongoDB URI options are key=value pairs.") from None + raise InvalidURI("MongoDB URI options are key=value pairs") from None options = _handle_security_options(options) @@ -389,7 +389,7 @@ def split_hosts(hosts: str, default_port: Optional[int] = DEFAULT_PORT) -> list[ nodes = [] for entity in hosts.split(","): if not entity: - raise ConfigurationError("Empty host (or extra comma in host list).") + raise ConfigurationError("Empty host (or extra comma in host list)") port = default_port # Unix socket entities don't have ports if entity.endswith(".sock"): @@ -502,7 +502,7 @@ def parse_uri( raise InvalidURI(f"Invalid URI scheme: URI must begin with '{SCHEME}' or '{SRV_SCHEME}'") if not scheme_free: - raise InvalidURI("Must provide at least one hostname or IP.") + raise InvalidURI("Must provide at least one hostname or IP") user = None passwd = None diff --git a/pymongo/write_concern.py b/pymongo/write_concern.py index 67c9549897..21faeebed0 100644 --- a/pymongo/write_concern.py +++ b/pymongo/write_concern.py @@ -74,7 +74,7 @@ def __init__( if wtimeout is not None: if not isinstance(wtimeout, int): - raise TypeError("wtimeout must be an integer") + raise TypeError(f"wtimeout must be an integer, not {type(wtimeout)}") if wtimeout < 0: raise ValueError("wtimeout cannot be less than 0") self.__document["wtimeout"] = wtimeout @@ -98,7 +98,7 @@ def __init__( raise ValueError("w cannot be less than 0") self.__acknowledged = w > 0 elif not isinstance(w, str): - raise TypeError("w must be an integer or string") + raise TypeError(f"w must be an integer or string, not {type(w)}") self.__document["w"] = w self.__server_default = not self.__document