diff --git a/PyPDF2/_encryption.py b/PyPDF2/_encryption.py index a5ef7872d..bc6870170 100644 --- a/PyPDF2/_encryption.py +++ b/PyPDF2/_encryption.py @@ -38,7 +38,7 @@ PdfObject, StreamObject, TextStringObject, - createStringObject, + create_string_object, ) @@ -172,7 +172,7 @@ def encrypt_object(self, obj: PdfObject) -> PdfObject: def decrypt_object(self, obj: PdfObject) -> PdfObject: if isinstance(obj, ByteStringObject) or isinstance(obj, TextStringObject): data = self.strCrypt.decrypt(obj.original_bytes) - obj = createStringObject(data) + obj = create_string_object(data) elif isinstance(obj, StreamObject): obj._data = self.stmCrypt.decrypt(obj._data) elif isinstance(obj, DictionaryObject): diff --git a/PyPDF2/_security.py b/PyPDF2/_security.py index 2450b6207..478c9999b 100644 --- a/PyPDF2/_security.py +++ b/PyPDF2/_security.py @@ -225,7 +225,7 @@ def _alg35( return val + (b"\x00" * 16), key -def RC4_encrypt(key: Union[str, bytes], plaintext: bytes) -> bytes: +def RC4_encrypt(key: Union[str, bytes], plaintext: bytes) -> bytes: # TODO S = list(range(256)) j = 0 for i in range(256): diff --git a/PyPDF2/_writer.py b/PyPDF2/_writer.py index abdf1caa7..b2ce6c382 100644 --- a/PyPDF2/_writer.py +++ b/PyPDF2/_writer.py @@ -68,7 +68,7 @@ TextStringObject, TreeObject, _create_bookmark, - createStringObject, + create_string_object, ) from .types import ( BookmarkTypes, @@ -108,7 +108,7 @@ def __init__(self) -> None: info = DictionaryObject() info.update( { - NameObject("/Producer"): createStringObject( + NameObject("/Producer"): create_string_object( codecs.BOM_UTF16_BE + "PyPDF2".encode("utf-16be") ) } @@ -215,18 +215,30 @@ def insertPage(self, page: PageObject, index: int = 0) -> None: # pragma: no co deprecate_with_replacement("insertPage", "insert_page") self.insert_page(page, index) - def get_page(self, pageNumber: int) -> PageObject: # TODO: PEP8 + def get_page( + self, page_number: Optional[int] = None, pageNumber: Optional[int] = None + ) -> PageObject: """ Retrieve a page by number from this PDF file. - :param int pageNumber: The page number to retrieve + :param int page_number: The page number to retrieve (pages begin at zero) - :return: the page at the index given by *pageNumber* + :return: the page at the index given by *page_number* :rtype: :class:`PageObject` """ + if pageNumber is not None: # pragma: no cover + if page_number is not None: + raise ValueError("Please only use the page_number parameter") + else: + deprecate_with_replacement( + "get_page(pageNumber)", "get_page(page_number)", "4.0.0" + ) + page_number = pageNumber + if page_number is None and pageNumber is None: # pragma: no cover + raise ValueError("Please specify the page_number") pages = cast(Dict[str, Any], self.get_object(self._pages)) # TODO: crude hack - return pages[PA.KIDS][pageNumber].get_object() + return pages[PA.KIDS][page_number].get_object() def getPage(self, pageNumber: int) -> PageObject: # pragma: no cover """ @@ -362,7 +374,7 @@ def add_js(self, javascript: str) -> None: NameObject("/JavaScript"): DictionaryObject( { NameObject(CA.NAMES): ArrayObject( - [createStringObject(js_string_name), js_indirect_object] + [create_string_object(js_string_name), js_indirect_object] ) } ) @@ -434,7 +446,7 @@ def add_attachment(self, filename: str, data: Union[str, bytes]) -> None: filespec.update( { NameObject(PA.TYPE): NameObject("/Filespec"), - NameObject("/F"): createStringObject( + NameObject("/F"): create_string_object( filename ), # Perhaps also try TextStringObject NameObject("/EF"): ef_entry, @@ -456,7 +468,7 @@ def add_attachment(self, filename: str, data: Union[str, bytes]) -> None: embedded_files_names_dictionary.update( { NameObject(CA.NAMES): ArrayObject( - [createStringObject(filename), filespec] + [create_string_object(filename), filespec] ) } ) @@ -787,7 +799,7 @@ def add_metadata(self, infos: Dict[str, Any]) -> None: """ args = {} for key, value in list(infos.items()): - args[NameObject(key)] = createStringObject(value) + args[NameObject(key)] = create_string_object(value) self.get_object(self._info).update(args) # type: ignore def addMetadata(self, infos: Dict[str, Any]) -> None: # pragma: no cover diff --git a/PyPDF2/filters.py b/PyPDF2/filters.py index 4fc71ab6b..cc988b69d 100644 --- a/PyPDF2/filters.py +++ b/PyPDF2/filters.py @@ -26,7 +26,11 @@ # POSSIBILITY OF SUCH DAMAGE. -"""Implementation of stream filters for PDF.""" +""" +Implementation of stream filters for PDF. + +See TABLE H.1 Abbreviations for standard filter names +""" __author__ = "Mathieu Fenniak" __author_email__ = "biziqe@mathieu.fenniak.net" @@ -43,7 +47,7 @@ except ImportError: from typing_extensions import Literal # type: ignore[misc] -from ._utils import b_, ord_, paeth_predictor +from ._utils import b_, deprecate_with_replacement, ord_, paeth_predictor from .constants import CcittFaxDecodeParameters as CCITT from .constants import ColorSpaces from .constants import FilterTypeAbbreviations as FTA @@ -76,40 +80,45 @@ def compress(data: bytes) -> bytes: class FlateDecode: @staticmethod def decode( - # TODO: PEP8 data: bytes, - decodeParms: Union[None, ArrayObject, DictionaryObject], + decode_parms: Union[None, ArrayObject, DictionaryObject] = None, + **kwargs: Any, ) -> bytes: """ :param data: flate-encoded data. - :param decodeParms: a dictionary of values, understanding the + :param decode_parms: a dictionary of values, understanding the "/Predictor": key only :return: the flate-decoded data. """ + if "decodeParms" in kwargs: # pragma: no cover + deprecate_with_replacement("decodeParms", "parameters", "4.0.0") + decode_parms = kwargs["decodeParms"] str_data = decompress(data) predictor = 1 - if decodeParms: + if decode_parms: try: - if isinstance(decodeParms, ArrayObject): - for decode_parm in decodeParms: + if isinstance(decode_parms, ArrayObject): + for decode_parm in decode_parms: if "/Predictor" in decode_parm: predictor = decode_parm["/Predictor"] else: - predictor = decodeParms.get("/Predictor", 1) + predictor = decode_parms.get("/Predictor", 1) except AttributeError: pass # Usually an array with a null object was read # predictor 1 == no predictor if predictor != 1: # The /Columns param. has 1 as the default value; see ISO 32000, # ยง7.4.4.3 LZWDecode and FlateDecode Parameters, Table 8 - if isinstance(decodeParms, ArrayObject): + if isinstance(decode_parms, ArrayObject): columns = 1 - for decode_parm in decodeParms: + for decode_parm in decode_parms: if "/Columns" in decode_parm: columns = decode_parm["/Columns"] else: - columns = 1 if decodeParms is None else decodeParms.get(LZW.COLUMNS, 1) + columns = ( + 1 if decode_parms is None else decode_parms.get(LZW.COLUMNS, 1) + ) # PNG prediction: if 10 <= predictor <= 15: @@ -171,17 +180,20 @@ class ASCIIHexDecode: @staticmethod def decode( - # TODO: PEP8 data: str, - decodeParms: Union[None, ArrayObject, DictionaryObject] = None, + decode_parms: Union[None, ArrayObject, DictionaryObject] = None, # noqa: F841 + **kwargs: Any, ) -> str: """ :param data: a str sequence of hexadecimal-encoded values to be converted into a base-7 ASCII string - :param decodeParms: + :param decode_parms: :return: a string conversion in base-7 ASCII, where each of its values v is such that 0 <= ord(v) <= 127. """ + if "decodeParms" in kwargs: # pragma: no cover + deprecate_with_replacement("decodeParms", "parameters", "4.0.0") + decode_parms = kwargs["decodeParms"] # noqa: F841 retval = "" hex_pair = "" index = 0 @@ -288,16 +300,19 @@ def decode(self) -> str: @staticmethod def decode( - # TODO: PEP8 data: bytes, - decodeParms: Union[None, ArrayObject, DictionaryObject] = None, + decode_parms: Union[None, ArrayObject, DictionaryObject] = None, + **kwargs: Any, ) -> str: """ :param data: ``bytes`` or ``str`` text to decode. - :param decodeParms: a dictionary of parameter values. + :param decode_parms: a dictionary of parameter values. :return: decoded data. :rtype: bytes """ + if "decodeParms" in kwargs: # pragma: no cover + deprecate_with_replacement("decodeParms", "parameters", "4.0.0") + decode_parms = kwargs["decodeParms"] # noqa: F841 return LZWDecode.Decoder(data).decode() @@ -307,8 +322,12 @@ class ASCII85Decode: @staticmethod def decode( data: Union[str, bytes], - decodeParms: Union[None, ArrayObject, DictionaryObject] = None, + decode_parms: Union[None, ArrayObject, DictionaryObject] = None, + **kwargs: Any, ) -> bytes: + if "decodeParms" in kwargs: # pragma: no cover + deprecate_with_replacement("decodeParms", "parameters", "4.0.0") + decode_parms = kwargs["decodeParms"] # noqa: F841 if isinstance(data, str): data = data.encode("ascii") group_index = b = 0 @@ -335,16 +354,26 @@ def decode( class DCTDecode: @staticmethod def decode( - data: bytes, decodeParms: Union[None, ArrayObject, DictionaryObject] = None + data: bytes, + decode_parms: Union[None, ArrayObject, DictionaryObject] = None, + **kwargs: Any, ) -> bytes: + if "decodeParms" in kwargs: # pragma: no cover + deprecate_with_replacement("decodeParms", "parameters", "4.0.0") + decode_parms = kwargs["decodeParms"] # noqa: F841 return data class JPXDecode: @staticmethod def decode( - data: bytes, decodeParms: Union[None, ArrayObject, DictionaryObject] = None + data: bytes, + decode_parms: Union[None, ArrayObject, DictionaryObject] = None, + **kwargs: Any, ) -> bytes: + if "decodeParms" in kwargs: # pragma: no cover + deprecate_with_replacement("decodeParms", "parameters", "4.0.0") + decode_parms = kwargs["decodeParms"] # noqa: F841 return data @@ -403,11 +432,14 @@ def _get_parameters( @staticmethod def decode( data: bytes, - # TODO: PEP8 - decodeParms: Union[None, ArrayObject, DictionaryObject] = None, + decode_parms: Union[None, ArrayObject, DictionaryObject] = None, height: int = 0, + **kwargs: Any, ) -> bytes: - parms = CCITTFaxDecode._get_parameters(decodeParms, height) + if "decodeParms" in kwargs: # pragma: no cover + deprecate_with_replacement("decodeParms", "parameters", "4.0.0") + decode_parms = kwargs["decodeParms"] + parms = CCITTFaxDecode._get_parameters(decode_parms, height) img_size = len(data) tiff_header_struct = "<2shlh" + "hhll" * 8 + "h" @@ -457,7 +489,7 @@ def decode( return tiff_header + data -def decodeStreamData(stream: Any) -> Union[str, bytes]: # utils.StreamObject +def decode_stream_data(stream: Any) -> Union[str, bytes]: # utils.StreamObject filters = stream.get(SA.FILTER, ()) if len(filters) and not isinstance(filters[0], NameObject): @@ -496,6 +528,11 @@ def decodeStreamData(stream: Any) -> Union[str, bytes]: # utils.StreamObject return data +def decodeStreamData(stream: Any) -> Union[str, bytes]: # pragma: no cover + deprecate_with_replacement("decodeStreamData", "decode_stream_data", "4.0.0") + return decode_stream_data(stream) + + def _xobj_to_image(x_object_obj: Dict[str, Any]) -> Tuple[Optional[str], bytes]: """ Users need to have the pillow package installed. diff --git a/PyPDF2/generic.py b/PyPDF2/generic.py index 64e813907..8767ec5e3 100644 --- a/PyPDF2/generic.py +++ b/PyPDF2/generic.py @@ -358,7 +358,16 @@ def readFromStream( return NumberObject.read_from_stream(stream) -def readHexStringFromStream( # TODO: PEP8 +def readHexStringFromStream( + stream: StreamType, +) -> Union["TextStringObject", "ByteStringObject"]: # pragma: no cover + deprecate_with_replacement( + "readHexStringFromStream", "read_hex_string_from_stream", "4.0.0" + ) + return read_hex_string_from_stream(stream) + + +def read_hex_string_from_stream( stream: StreamType, forced_encoding: Union[None, str, List[str], Dict[int, str]] = None, ) -> Union["TextStringObject", "ByteStringObject"]: @@ -379,10 +388,20 @@ def readHexStringFromStream( # TODO: PEP8 x += b"0" if len(x) == 2: txt += chr(int(x, base=16)) - return createStringObject(b_(txt), forced_encoding) + return create_string_object(b_(txt), forced_encoding) + + +def readStringFromStream( + stream: StreamType, + forced_encoding: Union[None, str, List[str], Dict[int, str]] = None, +) -> Union["TextStringObject", "ByteStringObject"]: # pragma: no cover + deprecate_with_replacement( + "readStringFromStream", "read_string_from_stream", "4.0.0" + ) + return read_string_from_stream(stream, forced_encoding) -def readStringFromStream( # TODO: PEP8 +def read_string_from_stream( stream: StreamType, forced_encoding: Union[None, str, List[str], Dict[int, str]] = None, ) -> Union["TextStringObject", "ByteStringObject"]: @@ -453,7 +472,7 @@ def readStringFromStream( # TODO: PEP8 msg = rf"Unexpected escaped string: {tok.decode('utf8')}" logger.warning(msg) txt += tok - return createStringObject(txt, forced_encoding) + return create_string_object(txt, forced_encoding) class ByteStringObject(bytes_type, PdfObject): # type: ignore @@ -802,7 +821,7 @@ def read_unsized_from_steam(stream: StreamType, pdf: Any) -> bytes: # PdfReader else: stream.seek(pos, 0) if "__streamdata__" in data: - return StreamObject.initializeFromDictionary(data) + return StreamObject.initialize_from_dictionary(data) else: retval = DictionaryObject() retval.update(data) @@ -820,14 +839,18 @@ class TreeObject(DictionaryObject): def __init__(self) -> None: DictionaryObject.__init__(self) - def hasChildren(self) -> bool: + def hasChildren(self) -> bool: # pragma: no cover + deprecate_with_replacement("hasChildren", "has_children", "4.0.0") + return self.has_children() + + def has_children(self) -> bool: return "/First" in self def __iter__(self) -> Any: return self.children() def children(self) -> Optional[Any]: - if not self.hasChildren(): + if not self.has_children(): return child = self["/First"] @@ -941,8 +964,11 @@ def remove_child(self, child: Any) -> None: if NameObject("/Prev") in child_obj: del child_obj[NameObject("/Prev")] - def emptyTree(self) -> None: - # TODO: Missing rename + def emptyTree(self) -> None: # pragma: no cover + deprecate_with_replacement("emptyTree", "empty_tree", "4.0.0") + self.empty_tree() + + def empty_tree(self) -> None: for child in self: child_obj = child.get_object() del child_obj[NameObject("/Parent")] @@ -1000,6 +1026,12 @@ def write_to_stream( @staticmethod def initializeFromDictionary( data: Dict[str, Any] + ) -> Union["EncodedStreamObject", "DecodedStreamObject"]: # pragma: no cover + return StreamObject.initialize_from_dictionary(data) + + @staticmethod + def initialize_from_dictionary( + data: Dict[str, Any] ) -> Union["EncodedStreamObject", "DecodedStreamObject"]: retval: Union["EncodedStreamObject", "DecodedStreamObject"] if SA.FILTER in data: @@ -1067,7 +1099,7 @@ def decodedSelf(self, value: DecodedStreamObject) -> None: # pragma: no cover self.decoded_self = value def get_data(self) -> Union[None, str, bytes]: - from .filters import decodeStreamData + from .filters import decode_stream_data if self.decoded_self is not None: # cached version of decoded object @@ -1076,7 +1108,7 @@ def get_data(self) -> Union[None, str, bytes]: # create decoded object decoded = DecodedStreamObject() - decoded._data = decodeStreamData(self) + decoded._data = decode_stream_data(self) for key, value in list(self.items()): if key not in (SA.LENGTH, SA.FILTER, SA.DECODE_PARMS): decoded[key] = value @@ -1116,9 +1148,9 @@ def __init__( stream_bytes = BytesIO(stream_data_bytes) # self.savstream = stream self.forced_encoding = forced_encoding - self.__parseContentStream(stream_bytes) + self.__parse_content_stream(stream_bytes) - def __parseContentStream(self, stream: StreamType) -> None: + def __parse_content_stream(self, stream: StreamType) -> None: # file("f:\\tmp.txt", "w").write(stream.read()) stream.seek(0, 0) operands: List[Union[int, str, PdfObject]] = [] @@ -1133,7 +1165,7 @@ def __parseContentStream(self, stream: StreamType) -> None: # begin inline image - a completely different parsing # mechanism is required, of course... thanks buddy... assert operands == [] - ii = self._readInlineImage(stream) + ii = self._read_inline_image(stream) self.operations.append((ii, b"INLINE IMAGE")) else: self.operations.append((operands, operator)) @@ -1149,7 +1181,7 @@ def __parseContentStream(self, stream: StreamType) -> None: else: operands.append(read_object(stream, None, self.forced_encoding)) - def _readInlineImage(self, stream: StreamType) -> Dict[str, Any]: + def _read_inline_image(self, stream: StreamType) -> Dict[str, Any]: # begin reading just after the "BI" - begin image # first read the dictionary of settings. settings = DictionaryObject() @@ -1231,7 +1263,7 @@ def _data(self) -> bytes: @_data.setter def _data(self, value: Union[str, bytes]) -> None: - self.__parseContentStream(BytesIO(b_(value))) + self.__parse_content_stream(BytesIO(b_(value))) def read_object( @@ -1252,13 +1284,13 @@ def read_object( if peek == b"<<": return DictionaryObject.read_from_stream(stream, pdf, forced_encoding) else: - return readHexStringFromStream(stream, forced_encoding) + return read_hex_string_from_stream(stream, forced_encoding) elif idx == 2: return ArrayObject.read_from_stream(stream, pdf, forced_encoding) elif idx == 3 or idx == 4: return BooleanObject.read_from_stream(stream) elif idx == 5: - return readStringFromStream(stream, forced_encoding) + return read_string_from_stream(stream, forced_encoding) elif idx == 6: return NullObject.read_from_stream(stream) elif idx == 7: @@ -1862,6 +1894,14 @@ def write_to_stream( def createStringObject( string: Union[str, bytes], forced_encoding: Union[None, str, List[str], Dict[int, str]] = None, +) -> Union[TextStringObject, ByteStringObject]: # pragma: no cover + deprecate_with_replacement("createStringObject", "create_string_object", "4.0.0") + return create_string_object(string, forced_encoding) + + +def create_string_object( + string: Union[str, bytes], + forced_encoding: Union[None, str, List[str], Dict[int, str]] = None, ) -> Union[TextStringObject, ByteStringObject]: """ Given a string, create a ByteStringObject or a TextStringObject to @@ -1903,7 +1943,7 @@ def createStringObject( except UnicodeDecodeError: return ByteStringObject(string) else: - raise TypeError("createStringObject should have str or unicode arg") + raise TypeError("create_string_object should have str or unicode arg") def _create_bookmark( @@ -1918,7 +1958,7 @@ def _create_bookmark( bookmark.update( { NameObject("/A"): action_ref, - NameObject("/Title"): createStringObject(title), + NameObject("/Title"): create_string_object(title), } ) diff --git a/PyPDF2/xmp.py b/PyPDF2/xmp.py index 08493c103..cbfd514e9 100644 --- a/PyPDF2/xmp.py +++ b/PyPDF2/xmp.py @@ -204,11 +204,16 @@ class XmpInformation(PdfObject): def __init__(self, stream: ContentStream) -> None: self.stream = stream doc_root: Document = parseString(self.stream.get_data()) - self.rdfRoot: XmlElement = doc_root.getElementsByTagNameNS( # TODO: PEP8 + self.rdf_root: XmlElement = doc_root.getElementsByTagNameNS( RDF_NAMESPACE, "RDF" )[0] self.cache: Dict[Any, Any] = {} + @property + def rdfRoot(self) -> XmlElement: # pragma: no cover + deprecate_with_replacement("rdfRoot", "rdf_root", "4.0.0") + return self.rdf_root + def write_to_stream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: @@ -226,7 +231,7 @@ def writeToStream( self.write_to_stream(stream, encryption_key) def get_element(self, about_uri: str, namespace: str, name: str) -> Iterator[Any]: - for desc in self.rdfRoot.getElementsByTagNameNS(RDF_NAMESPACE, "Description"): + for desc in self.rdf_root.getElementsByTagNameNS(RDF_NAMESPACE, "Description"): if desc.getAttributeNS(RDF_NAMESPACE, "about") == about_uri: attr = desc.getAttributeNodeNS(namespace, name) if attr is not None: @@ -245,7 +250,7 @@ def getElement( return self.get_element(aboutUri, namespace, name) def get_nodes_in_namespace(self, about_uri: str, namespace: str) -> Iterator[Any]: - for desc in self.rdfRoot.getElementsByTagNameNS(RDF_NAMESPACE, "Description"): + for desc in self.rdf_root.getElementsByTagNameNS(RDF_NAMESPACE, "Description"): if desc.getAttributeNS(RDF_NAMESPACE, "about") == about_uri: for i in range(desc.attributes.length): attr = desc.attributes.item(i) @@ -370,8 +375,7 @@ def _get_text(self, element: XmlElement) -> str: The name of the tool that created the PDF document. """ - # TODO: PEP8 - xmp_createDate = property( + xmp_create_date = property( _getter_single(XMP_NAMESPACE, "CreateDate", _converter_date) ) """ @@ -379,8 +383,17 @@ def _get_text(self, element: XmlElement) -> str: time are returned as a UTC datetime.datetime object. """ - # TODO: PEP8 - xmp_modifyDate = property( + @property + def xmp_createDate(self) -> datetime.datetime: # pragma: no cover + deprecate_with_replacement("xmp_createDate", "xmp_create_date", "4.0.0") + return self.xmp_create_date + + @xmp_createDate.setter + def xmp_createDate(self, value: datetime.datetime) -> None: # pragma: no cover + deprecate_with_replacement("xmp_createDate", "xmp_create_date", "4.0.0") + self.xmp_create_date = value + + xmp_modify_date = property( _getter_single(XMP_NAMESPACE, "ModifyDate", _converter_date) ) """ @@ -388,8 +401,17 @@ def _get_text(self, element: XmlElement) -> str: are returned as a UTC datetime.datetime object. """ - # TODO: PEP8 - xmp_metadataDate = property( + @property + def xmp_modifyDate(self) -> datetime.datetime: # pragma: no cover + deprecate_with_replacement("xmp_modifyDate", "xmp_modify_date", "4.0.0") + return self.xmp_modify_date + + @xmp_modifyDate.setter + def xmp_modifyDate(self, value: datetime.datetime) -> None: # pragma: no cover + deprecate_with_replacement("xmp_modifyDate", "xmp_modify_date", "4.0.0") + self.xmp_modify_date = value + + xmp_metadata_date = property( _getter_single(XMP_NAMESPACE, "MetadataDate", _converter_date) ) """ @@ -398,25 +420,62 @@ def _get_text(self, element: XmlElement) -> str: object. """ - # TODO: PEP8 - xmp_creatorTool = property(_getter_single(XMP_NAMESPACE, "CreatorTool")) + @property + def xmp_metadataDate(self) -> datetime.datetime: # pragma: no cover + deprecate_with_replacement("xmp_metadataDate", "xmp_metadata_date", "4.0.0") + return self.xmp_metadata_date + + @xmp_metadataDate.setter + def xmp_metadataDate(self, value: datetime.datetime) -> None: # pragma: no cover + deprecate_with_replacement("xmp_metadataDate", "xmp_metadata_date", "4.0.0") + self.xmp_metadata_date = value + + xmp_creator_tool = property(_getter_single(XMP_NAMESPACE, "CreatorTool")) """ The name of the first known tool used to create the resource. """ - # TODO: PEP8 - xmpmm_documentId = property(_getter_single(XMPMM_NAMESPACE, "DocumentID")) + @property + def xmp_creatorTool(self) -> str: # pragma: no cover + deprecate_with_replacement("xmp_creatorTool", "xmp_creator_tool") + return self.xmp_creator_tool + + @xmp_creatorTool.setter + def xmp_creatorTool(self, value: str) -> None: # pragma: no cover + deprecate_with_replacement("xmp_creatorTool", "xmp_creator_tool") + self.xmp_creator_tool = value + + xmpmm_document_id = property(_getter_single(XMPMM_NAMESPACE, "DocumentID")) """ The common identifier for all versions and renditions of this resource. """ - # TODO: PEP8 - xmpmm_instanceId = property(_getter_single(XMPMM_NAMESPACE, "InstanceID")) + @property + def xmpmm_documentId(self) -> str: # pragma: no cover + deprecate_with_replacement("xmpmm_documentId", "xmpmm_document_id") + return self.xmpmm_document_id + + @xmpmm_documentId.setter + def xmpmm_documentId(self, value: str) -> None: # pragma: no cover + deprecate_with_replacement("xmpmm_documentId", "xmpmm_document_id") + self.xmpmm_document_id = value + + xmpmm_instance_id = property(_getter_single(XMPMM_NAMESPACE, "InstanceID")) """ An identifier for a specific incarnation of a document, updated each time a file is saved. """ + @property + def xmpmm_instanceId(self) -> str: # pragma: no cover + deprecate_with_replacement("xmpmm_instanceId", "xmpmm_instance_id") + return self.xmpmm_instance_id + + @xmpmm_instanceId.setter + def xmpmm_instanceId(self, value: str) -> None: # pragma: no cover + deprecate_with_replacement("xmpmm_instanceId", "xmpmm_instance_id") + self.xmpmm_instance_id = value + @property def custom_properties(self) -> Dict[Any, Any]: """ diff --git a/make_changelog.py b/make_changelog.py index c280fc6cd..0c54839d7 100644 --- a/make_changelog.py +++ b/make_changelog.py @@ -19,7 +19,7 @@ def main(changelog_path: str): changes = get_formatted_changes(git_tag) print("-" * 80) print(changes) - # TODO: Write changes to changelog + new_version = version_bump(git_tag) today = datetime.now() header = f"Version {new_version}, {today:%Y-%m-%d}\n" diff --git a/tests/test_generic.py b/tests/test_generic.py index 20e3c4f0f..e6e2d5c63 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -21,11 +21,11 @@ RectangleObject, TextStringObject, TreeObject, - createStringObject, + create_string_object, encode_pdfdocencoding, + read_hex_string_from_stream, read_object, - readHexStringFromStream, - readStringFromStream, + read_string_from_stream, ) from . import get_pdf_from_url @@ -44,11 +44,11 @@ def test_number_object_exception(): NumberObject(1.5 * 2**10000) -def test_createStringObject_exception(): +def test_create_string_object_exception(): with pytest.raises(TypeError) as exc: - createStringObject(123) + create_string_object(123) assert ( # typeguard is not running - exc.value.args[0] == "createStringObject should have str or unicode arg" + exc.value.args[0] == "create_string_object should have str or unicode arg" ) or ( # typeguard is enabled 'type of argument "string" must be one of (str, bytes); got int instead' in exc.value.args[0] @@ -117,43 +117,43 @@ def test_indirect_object_premature(value): def test_readHexStringFromStream(): stream = BytesIO(b"a1>") - assert readHexStringFromStream(stream) == "\x10" + assert read_hex_string_from_stream(stream) == "\x10" def test_readHexStringFromStream_exception(): stream = BytesIO(b"") with pytest.raises(PdfStreamError) as exc: - readHexStringFromStream(stream) + read_hex_string_from_stream(stream) assert exc.value.args[0] == "Stream has ended unexpectedly" def test_readStringFromStream_exception(): stream = BytesIO(b"x") with pytest.raises(PdfStreamError) as exc: - readStringFromStream(stream) + read_string_from_stream(stream) assert exc.value.args[0] == "Stream has ended unexpectedly" def test_readStringFromStream_not_in_escapedict_no_digit(): stream = BytesIO(b"x\\y") with pytest.raises(PdfReadError) as exc: - readStringFromStream(stream) + read_string_from_stream(stream) assert exc.value.args[0] == "Stream has ended unexpectedly" def test_readStringFromStream_multichar_eol(): stream = BytesIO(b"x\\\n )") - assert readStringFromStream(stream) == " " + assert read_string_from_stream(stream) == " " def test_readStringFromStream_multichar_eol2(): stream = BytesIO(b"x\\\n\n)") - assert readStringFromStream(stream) == "" + assert read_string_from_stream(stream) == "" def test_readStringFromStream_excape_digit(): stream = BytesIO(b"x\\1a )") - assert readStringFromStream(stream) == "\x01 " + assert read_string_from_stream(stream) == "\x01 " def test_NameObject(): @@ -181,7 +181,7 @@ def test_destination_fit_r(): assert d.top == FloatObject(0) assert d.bottom == FloatObject(0) assert list(d) == [] - d.emptyTree() + d.empty_tree() def test_destination_fit_v(): @@ -403,7 +403,7 @@ def test_remove_child_in_tree(): tree.add_child(obj, writer) tree.remove_child(obj) tree.add_child(obj, writer) - tree.emptyTree() + tree.empty_tree() def test_dict_read_from_stream(): diff --git a/tests/test_xmp.py b/tests/test_xmp.py index 3bb825bd3..b9ae80eec 100644 --- a/tests/test_xmp.py +++ b/tests/test_xmp.py @@ -75,7 +75,7 @@ def test_regression_issue774(): def test_regression_issue914(): path = os.path.join(RESOURCE_ROOT, "issue-914-xmp-data.pdf") reader = PdfReader(path) - assert reader.xmp_metadata.xmp_modifyDate == datetime(2022, 4, 9, 15, 22, 43) + assert reader.xmp_metadata.xmp_modify_date == datetime(2022, 4, 9, 15, 22, 43) @pytest.mark.parametrize( @@ -99,9 +99,9 @@ def test_identity(x): def test_xmpmm(url, name, xmpmm_instance_id): reader = PdfReader(BytesIO(get_pdf_from_url(url, name=name))) xmp_metadata = reader.xmp_metadata - assert xmp_metadata.xmpmm_instanceId == xmpmm_instance_id + assert xmp_metadata.xmpmm_instance_id == xmpmm_instance_id # cache hit: - assert xmp_metadata.xmpmm_instanceId == xmpmm_instance_id + assert xmp_metadata.xmpmm_instance_id == xmpmm_instance_id def test_dc_description():