169 lines
5.7 KiB
Python
169 lines
5.7 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import warnings
|
|
from typing import Any, Optional
|
|
|
|
from pymongo import ASCENDING
|
|
from pymongo.common import MAX_MESSAGE_SIZE
|
|
from pymongo.errors import InvalidOperation
|
|
|
|
_SEEK_SET = os.SEEK_SET
|
|
_SEEK_CUR = os.SEEK_CUR
|
|
_SEEK_END = os.SEEK_END
|
|
|
|
EMPTY = b""
|
|
NEWLN = b"\n"
|
|
|
|
"""Default chunk size, in bytes."""
|
|
# Slightly under a power of 2, to work well with server's record allocations.
|
|
DEFAULT_CHUNK_SIZE = 255 * 1024
|
|
# The number of chunked bytes to buffer before calling insert_many.
|
|
_UPLOAD_BUFFER_SIZE = MAX_MESSAGE_SIZE
|
|
# The number of chunk documents to buffer before calling insert_many.
|
|
_UPLOAD_BUFFER_CHUNKS = 100000
|
|
# Rough BSON overhead of a chunk document not including the chunk data itself.
|
|
# Essentially len(encode({"_id": ObjectId(), "files_id": ObjectId(), "n": 1, "data": ""}))
|
|
_CHUNK_OVERHEAD = 60
|
|
|
|
_C_INDEX: dict[str, Any] = {"files_id": ASCENDING, "n": ASCENDING}
|
|
_F_INDEX: dict[str, Any] = {"filename": ASCENDING, "uploadDate": ASCENDING}
|
|
|
|
|
|
def _a_grid_in_property(
|
|
field_name: str,
|
|
docstring: str,
|
|
read_only: Optional[bool] = False,
|
|
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
|
|
if field_name == "length":
|
|
return self._file.get(field_name, 0)
|
|
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:
|
|
raise InvalidOperation(
|
|
"AsyncGridIn does not support __setattr__ after being closed(). Set the attribute before closing the file or use AsyncGridIn.set() instead"
|
|
)
|
|
self._file[field_name] = value
|
|
|
|
if read_only:
|
|
docstring += "\n\nThis attribute is read-only."
|
|
elif closed_only:
|
|
docstring = "{}\n\n{}".format(
|
|
docstring,
|
|
"This attribute is read-only and "
|
|
"can only be read after :meth:`close` "
|
|
"has been called.",
|
|
)
|
|
|
|
if not read_only and not closed_only:
|
|
return property(getter, setter, doc=docstring)
|
|
return property(getter, doc=docstring)
|
|
|
|
|
|
def _a_grid_out_property(field_name: str, docstring: str) -> Any:
|
|
"""Create a GridOut property."""
|
|
|
|
def a_getter(self: Any) -> Any:
|
|
if not self._file:
|
|
raise InvalidOperation(
|
|
"You must call GridOut.open() before accessing " "the %s property" % field_name
|
|
)
|
|
# Protect against PHP-237
|
|
if field_name == "length":
|
|
return self._file.get(field_name, 0)
|
|
return self._file.get(field_name, None)
|
|
|
|
docstring += "\n\nThis attribute is read-only."
|
|
return property(a_getter, doc=docstring)
|
|
|
|
|
|
def _grid_in_property(
|
|
field_name: str,
|
|
docstring: str,
|
|
read_only: Optional[bool] = False,
|
|
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
|
|
if field_name == "length":
|
|
return self._file.get(field_name, 0)
|
|
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
|
|
|
|
if read_only:
|
|
docstring += "\n\nThis attribute is read-only."
|
|
elif closed_only:
|
|
docstring = "{}\n\n{}".format(
|
|
docstring,
|
|
"This attribute is read-only and "
|
|
"can only be read after :meth:`close` "
|
|
"has been called.",
|
|
)
|
|
|
|
if not read_only and not closed_only:
|
|
return property(getter, setter, doc=docstring)
|
|
return property(getter, doc=docstring)
|
|
|
|
|
|
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.open()
|
|
|
|
# Protect against PHP-237
|
|
if field_name == "length":
|
|
return self._file.get(field_name, 0)
|
|
return self._file.get(field_name, None)
|
|
|
|
docstring += "\n\nThis attribute is read-only."
|
|
return property(getter, doc=docstring)
|
|
|
|
|
|
def _clear_entity_type_registry(entity: Any, **kwargs: Any) -> Any:
|
|
"""Clear the given database/collection object's type registry."""
|
|
codecopts = entity.codec_options.with_options(type_registry=None)
|
|
return entity.with_options(codec_options=codecopts, **kwargs)
|