From 787c784c5ec1c68737717321204943071722e8dc Mon Sep 17 00:00:00 2001 From: Martin Thoma Date: Thu, 26 May 2022 11:02:38 +0200 Subject: [PATCH] DEP: PEP8 renaming (#900) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PyPDF2 interface changes: * getXmpMetadata / xmpMetadata ➔ xmp_metadata * get_outlines ➔ _get_outlines (use outlines property instead) * getXmpMetadata ➔ xmp_metadata * getDestArray ➔ dest_array * additionalActions ➔ additional_actions * defaultValue ➔ default_value * mappingName ➔ mapping_name * altName ➔ alternate_name * fieldType ➔ field_type * ensureIsNumber ➔ _ensure_is_number * decodedSelf : decoded_self * addChild / removeChild ➔ add_child / remove_child * flateEncode ➔ flate_encode * getData / setData ➔ get_data / set_data DOC: Use the new PyPDF2 interface STY: Use reader/writer as variable names for PdfReader / PdfWriter MAINT: Let pytest capture many warnings Fixes: * add_named_destionation was a typo and thus removed * Add missing `PendingDeprecationWarning` in warnings * Add missing `stacklevel=2` in warnings * merge_rotated_scaled_translated_page ➔ mergeRotatedScaledTranslatedPage: That renaming was not part of the 1.28.0 release and the complete function should be deprecated; no point in adding a renamed one first * add_transformation: Add missing parameter type annotation --- PyPDF2/_merger.py | 22 +-- PyPDF2/_page.py | 16 +- PyPDF2/_reader.py | 39 ++-- PyPDF2/_writer.py | 34 +--- PyPDF2/filters.py | 4 +- PyPDF2/generic.py | 259 +++++++++++++++++++++---- PyPDF2/xmp.py | 10 +- README.md | 2 +- docs/modules/DocumentInformation.rst | 2 +- docs/user/adding-pdf-annotations.md | 2 +- docs/user/cropping-and-transforming.md | 4 +- docs/user/file-size.md | 4 +- docs/user/forms.md | 6 +- docs/user/reading-pdf-annotations.md | 2 +- sample-files | 2 +- tests/bench.py | 16 +- tests/test_basic_features.py | 6 +- tests/test_generic.py | 4 +- tests/test_merger.py | 42 ++-- tests/test_page.py | 55 ++++-- tests/test_reader.py | 76 +++++--- tests/test_workflows.py | 8 +- tests/test_writer.py | 14 +- tests/test_xmp.py | 13 +- 24 files changed, 428 insertions(+), 214 deletions(-) diff --git a/PyPDF2/_merger.py b/PyPDF2/_merger.py index f23c6fc20..ff248dbca 100644 --- a/PyPDF2/_merger.py +++ b/PyPDF2/_merger.py @@ -149,7 +149,7 @@ def merge( outline = [] if import_bookmarks: - outline = reader.get_outlines() + outline = reader.outlines outline = self._trim_outline(reader, outline, pages) if bookmark: @@ -162,7 +162,7 @@ def merge( else: self.bookmarks += outline - dests = reader.namedDestinations + dests = reader.named_destinations trimmed_dests = self._trim_dests(reader, dests, pages) self.named_dests += trimmed_dests @@ -296,7 +296,7 @@ def close(self) -> None: usage. """ self.pages = [] - for fo, _pdfr, mine in self.inputs: + for fo, _reader, mine in self.inputs: if mine: fo.close() @@ -690,7 +690,7 @@ def add_bookmark( dest = Destination( NameObject("/" + title + " bookmark"), page_ref, NameObject(fit), *zoom_args ) - dest_array = dest.getDestArray() + dest_array = dest.dest_array action.update( {NameObject("/D"): dest_array, NameObject("/S"): NameObject("/GoTo")} ) @@ -726,7 +726,7 @@ def add_bookmark( bookmark_ref = self.output._add_object(bookmark) parent = cast(Bookmark, parent.get_object()) assert parent is not None, "hint for mypy" - parent.addChild(bookmark_ref, self.output) + parent.add_child(bookmark_ref, self.output) return bookmark_ref @@ -742,18 +742,6 @@ def addNamedDestination(self, title: str, pagenum: int) -> None: return self.add_named_destination(title, pagenum) def add_named_destination(self, title: str, pagenum: int) -> None: - """ - .. deprecated:: 1.28.0 - Use :meth:`add_named_destionation` instead. - """ - warnings.warn( - "addNamedDestination is deprecated. Use add_named_destionation instead.", - DeprecationWarning, - stacklevel=2, - ) - return self.add_named_destionation(title, pagenum) - - def add_named_destionation(self, title: str, pagenum: int) -> None: """ Add a destination to the output. diff --git a/PyPDF2/_page.py b/PyPDF2/_page.py index 9933b1bbd..ef576f773 100644 --- a/PyPDF2/_page.py +++ b/PyPDF2/_page.py @@ -160,7 +160,7 @@ class Transformation: ----- >>> from PyPDF2 import Transformation >>> op = Transformation().scale(sx=2, sy=3).translate(tx=10, ty=20) - >>> page.mergeTransformedPage(page2, op) + >>> page.add_transformation(op) """ # 9.5.4 Coordinate Systems for 3D @@ -228,7 +228,7 @@ class PageObject(DictionaryObject): :meth:`get_page()` method of the :class:`PdfReader` class, but it is also possible to create an empty page with the - :meth:`createBlankPage()` static method. + :meth:`create_blank_page()` static method. :param pdf: PDF file the page belongs to. :param indirect_ref: Stores the original indirect reference to @@ -634,6 +634,8 @@ def mergeTransformedPage( warnings.warn( "page.mergeTransformedPage(page2, ctm) will be removed in PyPDF 2.0.0. " "Use page2.add_transformation(ctm); page.merge_page(page2) instead.", + PendingDeprecationWarning, + stacklevel=2, ) if isinstance(ctm, Transformation): ctm = ctm.ctm @@ -831,7 +833,7 @@ def mergeScaledTranslatedPage( op = Transformation().scale(scale, scale).translate(tx, ty) return self.mergeTransformedPage(page2, op, expand) - def merge_rotated_scaled_translated_page( + def mergeRotatedScaledTranslatedPage( self, page2: "PageObject", rotation: float, @@ -870,7 +872,9 @@ def merge_rotated_scaled_translated_page( self.mergeTransformedPage(page2, op, expand) def add_transformation( - self, ctm: CompressedTransformationMatrix, expand: bool = False + self, + ctm: Union[Transformation, CompressedTransformationMatrix], + expand: bool = False, ) -> None: """ Apply a transformation matrix to the page. @@ -1033,7 +1037,7 @@ def compress_content_streams(self) -> None: if content is not None: if not isinstance(content, ContentStream): content = ContentStream(content, self.pdf) - self[NameObject(PG.CONTENTS)] = content.flateEncode() + self[NameObject(PG.CONTENTS)] = content.flate_encode() def compressContentStreams(self) -> None: """ @@ -1112,6 +1116,8 @@ def extractText(self, Tj_sep: str = "", TJ_sep: str = "") -> str: """ warnings.warn( DEPR_MSG.format("Page.extractText", "Page.extract_text"), + PendingDeprecationWarning, + stacklevel=2, ) return self.extract_text(Tj_sep=Tj_sep, TJ_sep=TJ_sep) diff --git a/PyPDF2/_reader.py b/PyPDF2/_reader.py index cafe2817a..ab156c743 100644 --- a/PyPDF2/_reader.py +++ b/PyPDF2/_reader.py @@ -105,6 +105,7 @@ def convertToInt(d: bytes, size: int) -> Union[int, Tuple[Any, ...]]: "convertToInt will be removed with PyPDF2 2.0.0. " "Use convert_to_int instead.", PendingDeprecationWarning, + stacklevel=2, ) return convert_to_int(d, size) @@ -112,8 +113,7 @@ def convertToInt(d: bytes, size: int) -> Union[int, Tuple[Any, ...]]: class DocumentInformation(DictionaryObject): """ A class representing the basic document metadata provided in a PDF File. - This class is accessible through - :meth:`.getDocumentInfo()` + This class is accessible through :py:class:`PdfReader.metadata`. All text properties of the document metadata have *two* properties, eg. author and author_raw. The non-raw property will @@ -316,7 +316,7 @@ def xmp_metadata(self) -> Optional[XmpInformation]: """ try: self._override_encryption = True - return self.trailer[TK.ROOT].getXmpMetadata() # type: ignore + return self.trailer[TK.ROOT].xmp_metadata # type: ignore finally: self._override_encryption = False @@ -433,6 +433,8 @@ def namedDestinations(self) -> Dict[str, Any]: warnings.warn( "namedDestinations will be removed in PyPDF2 2.0.0. " "Use `named_destinations` instead.", + PendingDeprecationWarning, + stacklevel=2, ) return self.named_destinations @@ -668,17 +670,16 @@ def getNamedDestinations( @property def outlines(self) -> OutlinesType: - """Read-only property.""" - return self.get_outlines() - - def get_outlines( - self, node: Optional[DictionaryObject] = None, outlines: Optional[Any] = None - ) -> OutlinesType: """ - Retrieve the document outline present in the document. + Read-only property for outlines present in the document. :return: a nested list of :class:`Destinations`. """ + return self._get_outlines() + + def _get_outlines( + self, node: Optional[DictionaryObject] = None, outlines: Optional[Any] = None + ) -> OutlinesType: if outlines is None: outlines = [] catalog = cast(DictionaryObject, self.trailer[TK.ROOT]) @@ -710,7 +711,7 @@ def get_outlines( # check for sub-outlines if "/First" in node: sub_outlines: List[Any] = [] - self.get_outlines(cast(DictionaryObject, node["/First"]), sub_outlines) + self._get_outlines(cast(DictionaryObject, node["/First"]), sub_outlines) if sub_outlines: outlines.append(sub_outlines) @@ -726,14 +727,14 @@ def getOutlines( """ .. deprecated:: 1.28.0 - Use :meth:`get_outlines` instead. + Use :py:attr:`outlines` instead. """ warnings.warn( - "getOutlines will be removed in PyPDF2 2.0.0. Use get_outlines instead.", + "getOutlines will be removed in PyPDF2 2.0.0. Use the outlines attribute instead.", PendingDeprecationWarning, stacklevel=2, ) - return self.get_outlines(node, outlines) + return self._get_outlines(node, outlines) def _get_page_number_by_indirect( self, indirect_ref: Union[None, int, NullObject, IndirectObject] @@ -814,7 +815,7 @@ def _build_destination( try: return Destination(title, page, typ, *array) # type: ignore except PdfReadError: - warnings.warn("Unknown destination : " + title + " " + str(array)) + warnings.warn(f"Unknown destination: {title} {array}", PdfReadWarning) if self.strict: raise else: @@ -1031,7 +1032,7 @@ def _get_object_from_stream( assert obj_stm["/Type"] == "/ObjStm" # /N is the number of indirect objects in the stream assert idx < obj_stm["/N"] - stream_data = BytesIO(b_(obj_stm.getData())) # type: ignore + stream_data = BytesIO(b_(obj_stm.get_data())) # type: ignore for i in range(obj_stm["/N"]): # type: ignore read_non_whitespace(stream_data) stream_data.seek(-1, 1) @@ -1411,7 +1412,7 @@ def _find_startxref_pos(self, stream: StreamType) -> int: if not line.startswith(b_("startxref")): raise PdfReadError("startxref not found") startxref = int(line[9:].strip()) - warnings.warn("startxref on same line as offset") + warnings.warn("startxref on same line as offset", PdfReadWarning) else: line = self.read_next_end_line(stream) if line[:9] != b_("startxref"): @@ -1498,7 +1499,7 @@ def _read_pdf15_xref_stream( xrefstream = cast(ContentStream, read_object(stream, self)) assert xrefstream["/Type"] == "/XRef" self.cache_indirect_object(generation, idnum, xrefstream) - stream_data = BytesIO(b_(xrefstream.getData())) + stream_data = BytesIO(b_(xrefstream.get_data())) # Index pairs specify the subsections in the dictionary. If # none create one subsection that spans everything. idx_pairs = xrefstream.get("/Index", [0, xrefstream.get("/Size")]) @@ -1807,7 +1808,7 @@ def is_encrypted(self) -> bool: """ Read-only boolean property showing whether this PDF file is encrypted. Note that this property, if true, will remain true even after the - :meth:`decrypt()` method is called. + :meth:`decrypt()` method is called. """ return TK.ENCRYPT in self.trailer diff --git a/PyPDF2/_writer.py b/PyPDF2/_writer.py index a209e42af..15b971c5b 100644 --- a/PyPDF2/_writer.py +++ b/PyPDF2/_writer.py @@ -85,7 +85,7 @@ class PdfWriter: """ This class supports writing PDF files out, given pages produced by another - class (typically :class:`PdfReader`). + class (typically :class:`PdfReader`). """ def __init__(self) -> None: @@ -183,7 +183,7 @@ def set_need_appearances_writer(self) -> None: def add_page(self, page: PageObject) -> None: """ Add a page to this PDF file. The page is usually acquired from a - :class:`PdfReader` instance. + :class:`PdfReader` instance. :param PageObject page: The page to add to the document. Should be an instance of :class:`PageObject` @@ -206,7 +206,7 @@ def addPage(self, page: PageObject) -> None: def insert_page(self, page: PageObject, index: int = 0) -> None: """ Insert a page in this PDF file. The page is usually acquired from a - :class:`PdfReader` instance. + :class:`PdfReader` instance. :param PageObject page: The page to add to the document. This argument should be an instance of :class:`PageObject`. @@ -447,7 +447,7 @@ def add_attachment(self, filename: str, data: Union[str, bytes]) -> None: endobj """ file_entry = DecodedStreamObject() - file_entry.setData(data) + file_entry.set_data(data) file_entry.update({NameObject(PA.TYPE): NameObject("/EmbeddedFile")}) # The Filespec entry @@ -1040,7 +1040,7 @@ def add_bookmark_destination( parent = outline_ref parent = cast(TreeObject, parent.get_object()) - parent.addChild(dest_ref, self) + parent.add_child(dest_ref, self) return dest_ref @@ -1082,7 +1082,7 @@ def add_bookmark_dict( parent = parent.get_object() # type: ignore assert parent is not None, "hint for mypy" - parent.addChild(bookmark_ref, self) + parent.add_child(bookmark_ref, self) return bookmark_ref @@ -1136,7 +1136,7 @@ def add_bookmark( dest = Destination( NameObject("/" + title + " bookmark"), page_ref, NameObject(fit), *zoom_args ) - dest_array = dest.getDestArray() + dest_array = dest.dest_array action.update( {NameObject("/D"): dest_array, NameObject("/S"): NameObject("/GoTo")} ) @@ -1173,7 +1173,7 @@ def add_bookmark( assert parent is not None, "hint for mypy" parent_obj = cast(TreeObject, parent.get_object()) - parent_obj.addChild(bookmark_ref, self) + parent_obj.add_child(bookmark_ref, self) return bookmark_ref @@ -1579,7 +1579,7 @@ def add_link( dest = Destination( NameObject("/LinkName"), page_dest, NameObject(fit), *zoom_args ) # TODO: create a better name for the link - dest_array = dest.getDestArray() + dest_array = dest.dest_array lnk = DictionaryObject() lnk.update( @@ -1629,14 +1629,6 @@ def addLink( ] def _get_page_layout(self) -> Optional[LayoutType]: - """ - Get the page layout. - - See :meth:`setPageLayout()` for a description of valid layouts. - - :return: Page layout currently being used. - :rtype: str, None if not specified - """ try: return cast(LayoutType, self._root_object["/PageLayout"]) except KeyError: @@ -1771,14 +1763,6 @@ def pageLayout(self, layout: LayoutType) -> None: ] def _get_page_mode(self) -> Optional[PagemodeType]: - """ - Get the page mode. - See :meth:`setPageMode()` for a description - of valid modes. - - :return: Page mode currently being used. - :rtype: str, None if not specified. - """ try: return cast(PagemodeType, self._root_object["/PageMode"]) except KeyError: diff --git a/PyPDF2/filters.py b/PyPDF2/filters.py index f0a8ef946..6bf4619c3 100644 --- a/PyPDF2/filters.py +++ b/PyPDF2/filters.py @@ -502,7 +502,7 @@ def _xobj_to_image(x_object_obj: Dict[str, Any]) -> Tuple[Optional[str], bytes]: from PIL import Image size = (x_object_obj[IA.WIDTH], x_object_obj[IA.HEIGHT]) - data = x_object_obj.getData() # type: ignore + data = x_object_obj.get_data() # type: ignore if x_object_obj[IA.COLOR_SPACE] == ColorSpaces.DEVICE_RGB: mode: Literal["RGB", "P"] = "RGB" else: @@ -513,7 +513,7 @@ def _xobj_to_image(x_object_obj: Dict[str, Any]) -> Tuple[Optional[str], bytes]: extension = ".png" img = Image.frombytes(mode, size, data) if G.S_MASK in x_object_obj: # add alpha channel - alpha = Image.frombytes("L", size, x_object_obj[G.S_MASK].getData()) + alpha = Image.frombytes("L", size, x_object_obj[G.S_MASK].get_data()) img.putalpha(alpha) img_byte_arr = BytesIO() img.save(img_byte_arr, format="PNG") diff --git a/PyPDF2/generic.py b/PyPDF2/generic.py index d8d41717b..a6c70399d 100644 --- a/PyPDF2/generic.py +++ b/PyPDF2/generic.py @@ -676,7 +676,8 @@ def setdefault(self, key: Any, value: Optional[Any] = None) -> Any: def __getitem__(self, key: Any) -> PdfObject: return dict.__getitem__(self, key).get_object() - def getXmpMetadata(self) -> Optional[PdfObject]: # XmpInformation + @property + def xmp_metadata(self) -> Optional[PdfObject]: """ Retrieve XMP (Extensible Metadata Platform) data relevant to the this object, if available. @@ -698,15 +699,33 @@ def getXmpMetadata(self) -> Optional[PdfObject]: # XmpInformation self[NameObject("/Metadata")] = metadata return metadata + def getXmpMetadata(self) -> Optional[PdfObject]: # XmpInformation + """ + .. deprecated:: 1.28.3 + + Use :meth:`xmp_metadata` instead. + """ + warnings.warn( + "getXmpMetadata will be removed in PyPDF2 2.0.0. " + "Use xmp_metadata instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + return self.xmp_metadata + @property def xmpMetadata(self) -> Optional[PdfObject]: # XmpInformation """ - Read-only property that accesses the {@link - #DictionaryObject.getXmpData getXmpData} function. -

- Stability: Added in v1.12, will exist for all future v1.x releases. + .. deprecated:: 1.28.3 + + Use :meth:`xmp_metadata` instead. """ - return self.getXmpMetadata() + warnings.warn( + "xmpMetadata will be removed in PyPDF2 2.0.0. Use xmp_metadata instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + return self.xmp_metadata def write_to_stream( self, stream: StreamType, encryption_key: Union[None, str, bytes] @@ -891,6 +910,9 @@ def children(self) -> Optional[Any]: child = child["/Next"] # type: ignore def addChild(self, child: Any, pdf: Any) -> None: # PdfReader + self.add_child(child, pdf) + + def add_child(self, child: Any, pdf: Any) -> None: # PdfReader child_obj = child.get_object() child = pdf.get_reference(child_obj) assert isinstance(child, IndirectObject) @@ -916,6 +938,14 @@ def addChild(self, child: Any, pdf: Any) -> None: # PdfReader child_obj[NameObject("/Parent")] = parent_ref def removeChild(self, child: Any) -> None: + warnings.warn( + DEPR_MSG.format("removeChild", "remove_child"), + PendingDeprecationWarning, + stacklevel=2, + ) + self.remove_child(child) + + def remove_child(self, child: Any) -> None: child_obj = child.get_object() if NameObject("/Parent") not in child_obj: @@ -1003,7 +1033,25 @@ def emptyTree(self) -> None: class StreamObject(DictionaryObject): def __init__(self) -> None: self.__data: Optional[str] = None - self.decodedSelf: Optional[DecodedStreamObject] = None + self.decoded_self: Optional[DecodedStreamObject] = None + + @property + def decodedSelf(self) -> Optional["DecodedStreamObject"]: + warnings.warn( + DEPR_MSG.format("decodedSelf", "decoded_self"), + PendingDeprecationWarning, + stacklevel=2, + ) + return self.decoded_self + + @decodedSelf.setter + def decodedSelf(self, value: "DecodedStreamObject") -> None: + warnings.warn( + DEPR_MSG.format("decodedSelf", "decoded_self"), + PendingDeprecationWarning, + stacklevel=2, + ) + self.decoded_self = value @property def _data(self) -> Any: @@ -1044,6 +1092,14 @@ def initializeFromDictionary( return retval def flateEncode(self) -> "EncodedStreamObject": + warnings.warn( + DEPR_MSG.format("flateEncode", "flate_encode"), + PendingDeprecationWarning, + stacklevel=2, + ) + return self.flate_encode() + + def flate_encode(self) -> "EncodedStreamObject": from .filters import FlateDecode if SA.FILTER in self: @@ -1064,23 +1120,57 @@ def flateEncode(self) -> "EncodedStreamObject": class DecodedStreamObject(StreamObject): + def get_data(self) -> Any: + return self._data + + def set_data(self, data: Any) -> Any: + self._data = data + def getData(self) -> Any: + warnings.warn( + DEPR_MSG.format("decodedSelf", "decoded_self"), + PendingDeprecationWarning, + stacklevel=2, + ) return self._data def setData(self, data: Any) -> None: - self._data = data + warnings.warn( + DEPR_MSG.format("decodedSelf", "decoded_self"), + PendingDeprecationWarning, + stacklevel=2, + ) + self.set_data(data) class EncodedStreamObject(StreamObject): def __init__(self) -> None: - self.decodedSelf: Optional[DecodedStreamObject] = None + self.decoded_self: Optional[DecodedStreamObject] = None - def getData(self) -> Union[None, str, bytes]: + @property + def decodedSelf(self) -> Optional["DecodedStreamObject"]: + warnings.warn( + DEPR_MSG.format("decodedSelf", "decoded_self"), + PendingDeprecationWarning, + stacklevel=2, + ) + return self.decoded_self + + @decodedSelf.setter + def decodedSelf(self, value: DecodedStreamObject) -> None: + warnings.warn( + DEPR_MSG.format("decodedSelf", "decoded_self"), + PendingDeprecationWarning, + stacklevel=2, + ) + self.decoded_self = value + + def get_data(self) -> Union[None, str, bytes]: from .filters import decodeStreamData - if self.decodedSelf: + if self.decoded_self: # cached version of decoded object - return self.decodedSelf.getData() + return self.decoded_self.get_data() else: # create decoded object decoded = DecodedStreamObject() @@ -1089,10 +1179,10 @@ def getData(self) -> Union[None, str, bytes]: for key, value in list(self.items()): if key not in (SA.LENGTH, SA.FILTER, SA.DECODE_PARMS): decoded[key] = value - self.decodedSelf = decoded + self.decoded_self = decoded return decoded._data - def setData(self, data: Any) -> None: + def set_data(self, data: Any) -> None: raise PdfReadError("Creating EncodedStreamObject is not currently supported") @@ -1111,10 +1201,10 @@ def __init__(self, stream: Any, pdf: Any) -> None: if isinstance(stream, ArrayObject): data = b_("") for s in stream: - data += b_(s.get_object().getData()) + data += b_(s.get_object().get_data()) stream = BytesIO(b_(data)) else: - stream = BytesIO(b_(stream.getData())) + stream = BytesIO(b_(stream.get_data())) self.__parseContentStream(stream) def __parseContentStream(self, stream: StreamType) -> None: @@ -1293,13 +1383,21 @@ def __init__(self, arr: Tuple[float, float, float, float]) -> None: # must have four points assert len(arr) == 4 # automatically convert arr[x] into NumberObject(arr[x]) if necessary - ArrayObject.__init__(self, [self.ensureIsNumber(x) for x in arr]) # type: ignore + ArrayObject.__init__(self, [self._ensure_is_number(x) for x in arr]) # type: ignore - def ensureIsNumber(self, value: Any) -> Union[FloatObject, NumberObject]: + def _ensure_is_number(self, value: Any) -> Union[FloatObject, NumberObject]: if not isinstance(value, (NumberObject, FloatObject)): value = FloatObject(value) return value + def ensureIsNumber(self, value: Any) -> Union[FloatObject, NumberObject]: + warnings.warn( + "ensureIsNumber will be removed in PyPDF2 2.0.0. ", + PendingDeprecationWarning, + stacklevel=2, + ) + return self._ensure_is_number(value) + def __repr__(self) -> str: return "RectangleObject(%s)" % repr(list(self)) @@ -1393,7 +1491,7 @@ def lower_left(self) -> Tuple[decimal.Decimal, decimal.Decimal]: @lower_left.setter def lower_left(self, value: List[Any]) -> None: - self[0], self[1] = (self.ensureIsNumber(x) for x in value) + self[0], self[1] = (self._ensure_is_number(x) for x in value) @property def lower_right(self) -> Tuple[decimal.Decimal, decimal.Decimal]: @@ -1405,7 +1503,7 @@ def lower_right(self) -> Tuple[decimal.Decimal, decimal.Decimal]: @lower_right.setter def lower_right(self, value: List[Any]) -> None: - self[2], self[1] = (self.ensureIsNumber(x) for x in value) + self[2], self[1] = (self._ensure_is_number(x) for x in value) @property def upper_left(self) -> Tuple[decimal.Decimal, decimal.Decimal]: @@ -1417,7 +1515,7 @@ def upper_left(self) -> Tuple[decimal.Decimal, decimal.Decimal]: @upper_left.setter def upper_left(self, value: List[Any]) -> None: - self[0], self[3] = (self.ensureIsNumber(x) for x in value) + self[0], self[3] = (self._ensure_is_number(x) for x in value) @property def upper_right(self) -> Tuple[decimal.Decimal, decimal.Decimal]: @@ -1429,7 +1527,7 @@ def upper_right(self) -> Tuple[decimal.Decimal, decimal.Decimal]: @upper_right.setter def upper_right(self, value: List[Any]) -> None: - self[2], self[3] = (self.ensureIsNumber(x) for x in value) + self[2], self[3] = (self._ensure_is_number(x) for x in value) def getLowerLeft(self) -> Tuple[decimal.Decimal, decimal.Decimal]: warnings.warn( @@ -1477,7 +1575,7 @@ def setLowerRight(self, value: Tuple[float, float]) -> None: PendingDeprecationWarning, stacklevel=2, ) - self[2], self[1] = (self.ensureIsNumber(x) for x in value) + self[2], self[1] = (self._ensure_is_number(x) for x in value) def setUpperLeft(self, value: Tuple[float, float]) -> None: warnings.warn( @@ -1485,7 +1583,7 @@ def setUpperLeft(self, value: Tuple[float, float]) -> None: PendingDeprecationWarning, stacklevel=2, ) - self[0], self[3] = (self.ensureIsNumber(x) for x in value) + self[0], self[3] = (self._ensure_is_number(x) for x in value) def setUpperRight(self, value: Tuple[float, float]) -> None: warnings.warn( @@ -1493,7 +1591,7 @@ def setUpperRight(self, value: Tuple[float, float]) -> None: PendingDeprecationWarning, stacklevel=2, ) - self[2], self[3] = (self.ensureIsNumber(x) for x in value) + self[2], self[3] = (self._ensure_is_number(x) for x in value) @property def width(self) -> decimal.Decimal: @@ -1587,7 +1685,7 @@ def upperRight(self, value: Tuple[decimal.Decimal, decimal.Decimal]) -> None: class Field(TreeObject): """ A class representing a field dictionary. This class is accessed through - :meth:`getFields()` + :meth:`get_fields()` """ def __init__(self, data: Dict[str, Any]) -> None: @@ -1611,12 +1709,26 @@ def __init__(self, data: Dict[str, Any]) -> None: pass # TABLE 8.69 Entries common to all field dictionaries - @property - def fieldType(self) -> Optional[NameObject]: + def field_type(self) -> Optional[NameObject]: """Read-only property accessing the type of this field.""" return self.get("/FT") + @property + def fieldType(self) -> Optional[NameObject]: + """ + .. deprecated:: 1.28.3 + + Use :py:attr:`field_type` instead. + """ + warnings.warn( + "fieldType will be removed in PyPDF2 2.0.0. " + "Use the field_type property instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + return self.field_type + @property def parent(self) -> Optional[DictionaryObject]: """Read-only property accessing the parent of this field.""" @@ -1633,19 +1745,49 @@ def name(self) -> Optional[str]: return self.get("/T") @property - def altName(self) -> Optional[str]: + def alternate_name(self) -> Optional[str]: """Read-only property accessing the alternate name of this field.""" return self.get("/TU") @property - def mappingName(self) -> Optional[str]: + def altName(self) -> Optional[str]: + """ + .. deprecated:: 1.28.3 + + Use :py:attr:`alternate_name` instead. + """ + warnings.warn( + "altName will be removed in PyPDF2 2.0.0. " + "Use the alternate_name property instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + return self.alternate_name + + @property + def mapping_name(self) -> Optional[str]: """ Read-only property accessing the mapping name of this field. This name is used by PyPDF2 as a key in the dictionary returned by - :meth:`getFields()` + :meth:`get_fields()` """ return self.get("/TM") + @property + def mappingName(self) -> Optional[str]: + """ + .. deprecated:: 1.28.3 + + Use :py:attr:`mapping_name` instead. + """ + warnings.warn( + "mappingName will be removed in PyPDF2 2.0.0. " + "Use the mapping_name property instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + return self.mapping_name + @property def flags(self) -> Optional[int]: """ @@ -1663,12 +1805,27 @@ def value(self) -> Optional[Any]: return self.get("/V") @property - def defaultValue(self) -> Optional[Any]: + def default_value(self) -> Optional[Any]: """Read-only property accessing the default value of this field.""" return self.get("/DV") @property - def additionalActions(self) -> Optional[DictionaryObject]: + def defaultValue(self) -> Optional[Any]: + """ + .. deprecated:: 1.28.3 + + Use :py:attr:`default_value` instead. + """ + warnings.warn( + "defaultValue will be removed in PyPDF2 2.0.0. " + "Use the default_value property instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + return self.default_value + + @property + def additional_actions(self) -> Optional[DictionaryObject]: """ Read-only property accessing the additional actions dictionary. This dictionary defines the field's behavior in response to trigger events. @@ -1676,6 +1833,21 @@ def additionalActions(self) -> Optional[DictionaryObject]: """ return self.get("/AA") + @property + def additionalActions(self) -> Optional[DictionaryObject]: + """ + .. deprecated:: 1.28.3 + + Use :py:attr:`additional_actions` instead. + """ + warnings.warn( + "additionalActions will be removed in PyPDF2 2.0.0. " + "Use the additional_actions property instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + return self.additional_actions + class Destination(TreeObject): """ @@ -1745,7 +1917,8 @@ def __init__( else: raise PdfReadError("Unknown Destination Type: %r" % typ) - def getDestArray(self) -> ArrayObject: + @property + def dest_array(self) -> ArrayObject: return ArrayObject( [self.raw_get("/Page"), self["/Type"]] + [ @@ -1755,6 +1928,20 @@ def getDestArray(self) -> ArrayObject: ] ) + def getDestArray(self) -> ArrayObject: + """ + .. deprecated:: 1.28.3 + + Use :py:attr:`dest_array` instead. + """ + warnings.warn( + "getDestArray will be removed in PyPDF2 2.0.0. " + "Use the dest_array property instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + return self.dest_array + def write_to_stream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: @@ -1762,7 +1949,7 @@ def write_to_stream( key = NameObject("/D") key.write_to_stream(stream, encryption_key) stream.write(b_(" ")) - value = self.getDestArray() + value = self.dest_array value.write_to_stream(stream, encryption_key) key = NameObject("/S") @@ -1865,7 +2052,7 @@ def write_to_stream( key = NameObject("/Dest") key.write_to_stream(stream, encryption_key) stream.write(b_(" ")) - value = self.getDestArray() + value = self.dest_array value.write_to_stream(stream, encryption_key) stream.write(b_("\n")) stream.write(b_(">>")) diff --git a/PyPDF2/xmp.py b/PyPDF2/xmp.py index cb2fc2288..ee81c06a4 100644 --- a/PyPDF2/xmp.py +++ b/PyPDF2/xmp.py @@ -98,7 +98,7 @@ def get(self: Any) -> Optional[Any]: if cached: return cached retval = [] - for element in self.getElement("", namespace, name): + for element in self.get_element("", namespace, name): bags = element.getElementsByTagNameNS(RDF_NAMESPACE, "Bag") if len(bags): for bag in bags: @@ -186,12 +186,12 @@ def get(self: Any) -> Optional[Any]: class XmpInformation(PdfObject): """ An object that represents Adobe XMP metadata. - Usually accessed by :meth:`getXmpMetadata()` + Usually accessed by :py:attr:`xmp_metadata()` """ def __init__(self, stream: ContentStream) -> None: self.stream = stream - doc_root: Document = parseString(self.stream.getData()) + doc_root: Document = parseString(self.stream.get_data()) self.rdfRoot: XmlElement = doc_root.getElementsByTagNameNS( RDF_NAMESPACE, "RDF" )[0] @@ -233,6 +233,8 @@ def getElement(self, aboutUri: str, namespace: str, name: str) -> Any: """ warnings.warn( DEPR_MSG.format("getElement", "get_element"), + PendingDeprecationWarning, + stacklevel=2, ) return self.get_element(aboutUri, namespace, name) @@ -255,6 +257,8 @@ def getNodesInNamespace(self, aboutUri: str, namespace: str) -> Any: """ warnings.warn( DEPR_MSG.format("getNodesInNamespace", "get_nodes_in_namespace"), + PendingDeprecationWarning, + stacklevel=2, ) return self.get_nodes_in_namespace(aboutUri, namespace) diff --git a/README.md b/README.md index 46522cf57..e918f6620 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ pip install PyPDF2 from PyPDF2 import PdfReader reader = PdfReader("example.pdf") -number_of_pages = reader.numPages +number_of_pages = len(reader.pages) page = reader.pages[0] text = page.extract_text() ``` diff --git a/docs/modules/DocumentInformation.rst b/docs/modules/DocumentInformation.rst index af1ffc9ab..8a154d411 100644 --- a/docs/modules/DocumentInformation.rst +++ b/docs/modules/DocumentInformation.rst @@ -1,7 +1,7 @@ The DocumentInformation Class ----------------------------- -.. autoclass:: PyPDF2.generic.DocumentInformation +.. autoclass:: PyPDF2._reader.DocumentInformation :members: :undoc-members: :show-inheritance: diff --git a/docs/user/adding-pdf-annotations.md b/docs/user/adding-pdf-annotations.md index 3be2149de..d174e1114 100644 --- a/docs/user/adding-pdf-annotations.md +++ b/docs/user/adding-pdf-annotations.md @@ -6,7 +6,7 @@ from PyPDF2 import PdfWriter writer = PdfWriter() -writer.addBlankPage(width=200, height=200) +writer.add_blank_page(width=200, height=200) data = b"any bytes - typically read from a file" writer.add_attachment("smile.png", data) diff --git a/docs/user/cropping-and-transforming.md b/docs/user/cropping-and-transforming.md index f411d8a41..dab4ba663 100644 --- a/docs/user/cropping-and-transforming.md +++ b/docs/user/cropping-and-transforming.md @@ -50,7 +50,7 @@ page_base.merge_page(page_box) # Write the result back writer = PdfWriter() -writer.addPage(page_base) +writer.add_page(page_base) with open("merged-foo.pdf", "wb") as fp: writer.write(fp) ``` @@ -76,7 +76,7 @@ page_base.merge_page(page_box) # Write the result back writer = PdfWriter() -writer.addPage(page_base) +writer.add_page(page_base) with open("merged-foo.pdf", "wb") as fp: writer.write(fp) ``` diff --git a/docs/user/file-size.md b/docs/user/file-size.md index 17a866bcb..7b4b93df8 100644 --- a/docs/user/file-size.md +++ b/docs/user/file-size.md @@ -30,8 +30,8 @@ reader = PyPDF2.PdfReader("example.pdf") writer = PyPDF2.PdfWriter() for page in reader.pages: - page.compressContentStreams() - writer.addPage(page) + page.compress_content_streams() + writer.add_page(page) with open("out.pdf", "wb") as f: writer.write(f) diff --git a/docs/user/forms.md b/docs/user/forms.md index ad2408099..711723b74 100644 --- a/docs/user/forms.md +++ b/docs/user/forms.md @@ -6,7 +6,7 @@ from PyPDF2 import PdfReader reader = PdfReader("form.pdf") -fields = reader.getFormTextFields() +fields = reader.get_form_text_fields() fields == {"key": "value", "key2": "value2"} ``` @@ -23,7 +23,9 @@ fields = reader.get_fields() writer.add_page(page) -writer.updatePageFormFieldValues(writer.pages[0], {"fieldname": "some filled in text"}) +writer.update_page_form_field_values( + writer.pages[0], {"fieldname": "some filled in text"} +) # write "output" to PyPDF2-output.pdf with open("filled-out.pdf", "wb") as output_stream: diff --git a/docs/user/reading-pdf-annotations.md b/docs/user/reading-pdf-annotations.md index 91aa4c76b..8c01fe728 100644 --- a/docs/user/reading-pdf-annotations.md +++ b/docs/user/reading-pdf-annotations.md @@ -63,5 +63,5 @@ for page in reader.pages: subtype = annot.get_object()["/Subtype"] if subtype == "/FileAttachment": fileobj = annotobj["/FS"] - attachments[fileobj["/F"]] = fileobj["/EF"]["/F"].getData() + attachments[fileobj["/F"]] = fileobj["/EF"]["/F"].get_data() ``` diff --git a/sample-files b/sample-files index 41b5cd4f7..d7ce88b71 160000 --- a/sample-files +++ b/sample-files @@ -1 +1 @@ -Subproject commit 41b5cd4f774f8fbd8ac42d93b9962f0376352a15 +Subproject commit d7ce88b71820fccaaa4738aa37cbace51f3ed3d9 diff --git a/tests/bench.py b/tests/bench.py index 8868a9f29..f340c8a85 100644 --- a/tests/bench.py +++ b/tests/bench.py @@ -20,12 +20,12 @@ def page_ops(pdf_path, password): page = reader.pages[0] page.mergeRotatedScaledPage(page, 90, 1, 1) page.mergeScaledTranslatedPage(page, 1, 1, 1) - page.merge_rotated_scaled_translated_page(page, 90, 1, 1, 1, 1) + page.mergeRotatedScaledTranslatedPage(page, 90, 1, 1, 1, 1) page.add_transformation((1, 0, 0, 0, 0, 0)) page.scale(2, 2) page.scale_by(0.5) page.scale_to(100, 100) - page.compressContentStreams() + page.compress_content_streams() page.extract_text() @@ -53,9 +53,9 @@ def merge(): file_merger.append(pdf_forms) # Merging an encrypted file - pdfr = PyPDF2.PdfReader(pdf_pw) - pdfr.decrypt("openpassword") - file_merger.append(pdfr) + reader = PyPDF2.PdfReader(pdf_pw) + reader.decrypt("openpassword") + file_merger.append(reader) # PdfReader object: file_merger.append(PyPDF2.PdfReader(pdf_path, "rb"), bookmark=True) @@ -76,8 +76,10 @@ def merge(): file_merger.close() # Check if bookmarks are correct - pdfr = PyPDF2.PdfReader(tmp_path) - assert [el.title for el in pdfr.get_outlines() if isinstance(el, Destination)] == [ + reader = PyPDF2.PdfReader(tmp_path) + assert [ + el.title for el in reader._get_outlines() if isinstance(el, Destination) + ] == [ "A bookmark", "Foo", "Bar", diff --git a/tests/test_basic_features.py b/tests/test_basic_features.py index a07aab358..5f931dd76 100644 --- a/tests/test_basic_features.py +++ b/tests/test_basic_features.py @@ -1,5 +1,7 @@ import os +import pytest + from PyPDF2 import PdfReader, PdfWriter TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) @@ -21,7 +23,9 @@ def test_basic_features(): writer.add_page(reader.pages[0].rotate_clockwise(90)) # add page 3 from input1, rotated the other way: - writer.add_page(reader.pages[0].rotateCounterClockwise(90)) + with pytest.warns(PendingDeprecationWarning): + rotated = reader.pages[0].rotateCounterClockwise(90) + writer.add_page(rotated) # alt: output.addPage(input1.pages[0].rotate_clockwise(270)) # add page 4 from input1, but first add a watermark from another PDF: diff --git a/tests/test_generic.py b/tests/test_generic.py index dbc48268f..474436ca2 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -235,7 +235,9 @@ def test_DictionaryObject_key_is_no_pdfobject(): def test_DictionaryObject_xmp_meta(): do = DictionaryObject({NameObject("/S"): NameObject("/GoTo")}) - assert do.xmpMetadata is None + assert do.xmp_metadata is None + with pytest.warns(PendingDeprecationWarning): + assert do.xmpMetadata is None def test_DictionaryObject_value_is_no_pdfobject(): diff --git a/tests/test_merger.py b/tests/test_merger.py index 92d193128..2d137fcad 100644 --- a/tests/test_merger.py +++ b/tests/test_merger.py @@ -17,40 +17,42 @@ def test_merge(): pdf_forms = os.path.join(RESOURCE_ROOT, "pdflatex-forms.pdf") pdf_pw = os.path.join(RESOURCE_ROOT, "libreoffice-writer-password.pdf") - file_merger = PyPDF2.PdfMerger() + merger = PyPDF2.PdfMerger() # string path: - file_merger.append(pdf_path) - file_merger.append(outline) - file_merger.append(pdf_path, pages=PyPDF2.pagerange.PageRange(slice(0, 0))) - file_merger.append(pdf_forms) + merger.append(pdf_path) + merger.append(outline) + merger.append(pdf_path, pages=PyPDF2.pagerange.PageRange(slice(0, 0))) + merger.append(pdf_forms) # Merging an encrypted file - pdfr = PyPDF2.PdfReader(pdf_pw) - pdfr.decrypt("openpassword") - file_merger.append(pdfr) + reader = PyPDF2.PdfReader(pdf_pw) + reader.decrypt("openpassword") + merger.append(reader) # PdfReader object: - file_merger.append(PyPDF2.PdfReader(pdf_path), bookmark="foo") + merger.append(PyPDF2.PdfReader(pdf_path), bookmark="foo") # File handle with open(pdf_path, "rb") as fh: - file_merger.append(fh) + merger.append(fh) - bookmark = file_merger.add_bookmark("A bookmark", 0) - file_merger.add_bookmark("deeper", 0, parent=bookmark) - file_merger.add_metadata({"author": "Martin Thoma"}) - file_merger.add_named_destination("title", 0) - file_merger.set_page_layout("/SinglePage") - file_merger.set_page_mode("/UseThumbs") + bookmark = merger.add_bookmark("A bookmark", 0) + merger.add_bookmark("deeper", 0, parent=bookmark) + merger.add_metadata({"author": "Martin Thoma"}) + merger.add_named_destination("title", 0) + merger.set_page_layout("/SinglePage") + merger.set_page_mode("/UseThumbs") tmp_path = "dont_commit_merged.pdf" - file_merger.write(tmp_path) - file_merger.close() + merger.write(tmp_path) + merger.close() # Check if bookmarks are correct - pdfr = PyPDF2.PdfReader(tmp_path) - assert [el.title for el in pdfr.get_outlines() if isinstance(el, Destination)] == [ + reader = PyPDF2.PdfReader(tmp_path) + assert [ + el.title for el in reader._get_outlines() if isinstance(el, Destination) + ] == [ "A bookmark", "Foo", "Bar", diff --git a/tests/test_page.py b/tests/test_page.py index 5147442bb..0eb60461b 100644 --- a/tests/test_page.py +++ b/tests/test_page.py @@ -67,15 +67,22 @@ def test_page_operations(pdf_path, password): reader.decrypt(password) page: PageObject = reader.pages[0] - page.merge_rotated_scaled_translated_page( - page, 90, scale=1, tx=1, ty=1, expand=True - ) - page.add_transformation([1, 0, 0, 0, 0, 0]) + with pytest.warns(PendingDeprecationWarning): + page.mergeRotatedScaledTranslatedPage( + page, 90, scale=1, tx=1, ty=1, expand=True + ) + page.add_transformation((1, 0, 0, 0, 0, 0)) page.scale(2, 2) - page.scaleBy(0.5) - page.scaleTo(100, 100) - page.compressContentStreams() - page.extractText() + page.scale_by(0.5) + page.scale_to(100, 100) + page.compress_content_streams() + page.extract_text() + with pytest.warns(PendingDeprecationWarning): + page.scaleBy(0.5) + with pytest.warns(PendingDeprecationWarning): + page.scaleTo(100, 100) + with pytest.warns(PendingDeprecationWarning): + page.extractText() def test_transformation_equivalence(): @@ -98,7 +105,8 @@ def test_transformation_equivalence(): # Option 2: The old way page_box2 = deepcopy(page_box) page_base2 = deepcopy(page_base) - page_base2.mergeTransformedPage(page_box2, op, expand=False) + with pytest.warns(PendingDeprecationWarning): + page_base2.mergeTransformedPage(page_box2, op, expand=False) # Should be the smae assert page_base1[NameObject(PG.CONTENTS)] == page_base2[NameObject(PG.CONTENTS)] @@ -124,16 +132,23 @@ def test_page_transformations(): reader = PdfReader(pdf_path) page: PageObject = reader.pages[0] - page.mergeRotatedPage(page, 90, expand=True) - page.mergeRotatedScaledPage(page, 90, 1, expand=True) - page.merge_rotated_scaled_translated_page( - page, 90, scale=1, tx=1, ty=1, expand=True - ) - page.mergeRotatedTranslatedPage(page, 90, 100, 100, expand=False) - page.mergeScaledPage(page, 2, expand=False) - page.mergeScaledTranslatedPage(page, 1, 1, 1) - page.mergeTranslatedPage(page, 100, 100, expand=False) - page.add_transformation([1, 0, 0, 0, 0, 0]) + with pytest.warns(PendingDeprecationWarning): + page.mergeRotatedPage(page, 90, expand=True) + with pytest.warns(PendingDeprecationWarning): + page.mergeRotatedScaledPage(page, 90, 1, expand=True) + with pytest.warns(PendingDeprecationWarning): + page.mergeRotatedScaledTranslatedPage( + page, 90, scale=1, tx=1, ty=1, expand=True + ) + with pytest.warns(PendingDeprecationWarning): + page.mergeRotatedTranslatedPage(page, 90, 100, 100, expand=False) + with pytest.warns(PendingDeprecationWarning): + page.mergeScaledPage(page, 2, expand=False) + with pytest.warns(PendingDeprecationWarning): + page.mergeScaledTranslatedPage(page, 1, 1, 1) + with pytest.warns(PendingDeprecationWarning): + page.mergeTranslatedPage(page, 100, 100, expand=False) + page.add_transformation((1, 0, 0, 0, 0, 0)) @pytest.mark.parametrize( @@ -153,7 +168,7 @@ def test_compress_content_streams(pdf_path, password): if password: reader.decrypt(password) for page in reader.pages: - page.compressContentStreams() + page.compress_content_streams() def test_page_properties(): diff --git a/tests/test_reader.py b/tests/test_reader.py index c158b456d..89dda0387 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -10,7 +10,7 @@ from PyPDF2.constants import ImageAttributes as IA from PyPDF2.constants import PageAttributes as PG from PyPDF2.constants import Ressources as RES -from PyPDF2.errors import PdfReadError +from PyPDF2.errors import PdfReadError, PdfReadWarning from PyPDF2.filters import _xobj_to_image TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) @@ -64,7 +64,9 @@ def test_get_num_pages(src, num_pages): def test_read_metadata(pdf_path, expected): with open(pdf_path, "rb") as inputfile: reader = PdfReader(inputfile) - docinfo = reader.documentInfo + with pytest.warns(PendingDeprecationWarning): + docinfo = reader.documentInfo + assert docinfo is not None metadict = dict(docinfo) assert metadict == expected docinfo.title @@ -117,7 +119,7 @@ def test_get_attachments(src): annotobj = annotation.get_object() if annotobj[IA.SUBTYPE] == "/FileAttachment": fileobj = annotobj["/FS"] - attachments[fileobj["/F"]] = fileobj["/EF"]["/F"].getData() + attachments[fileobj["/F"]] = fileobj["/EF"]["/F"].get_data() return attachments @@ -130,7 +132,7 @@ def test_get_attachments(src): ) def test_get_outlines(src, outline_elements): reader = PdfReader(src) - outlines = reader.get_outlines() + outlines = reader._get_outlines() assert len(outlines) == outline_elements @@ -228,7 +230,8 @@ def test_get_images_raw(strict, with_prev_0, startx_correction, should_fail): pdf_stream = io.BytesIO(pdf_data) if should_fail: with pytest.raises(PdfReadError) as exc: - PdfReader(pdf_stream, strict=strict) + with pytest.warns(PdfReadWarning): + PdfReader(pdf_stream, strict=strict) assert exc.type == PdfReadError if startx_correction == -1: assert ( @@ -236,15 +239,18 @@ def test_get_images_raw(strict, with_prev_0, startx_correction, should_fail): == "/Prev=0 in the trailer (try opening with strict=False)" ) else: - PdfReader(pdf_stream, strict=strict) + with pytest.warns(PdfReadWarning): + PdfReader(pdf_stream, strict=strict) def test_issue297(): path = os.path.join(RESOURCE_ROOT, "issue-297.pdf") with pytest.raises(PdfReadError) as exc: - reader = PdfReader(path, strict=True) + with pytest.warns(PdfReadWarning): + reader = PdfReader(path, strict=True) assert "Broken xref table" in exc.value.args[0] - reader = PdfReader(path, strict=False) + with pytest.warns(PdfReadWarning): + reader = PdfReader(path, strict=False) reader.pages[0] @@ -302,16 +308,16 @@ def test_get_form(src, expected, expected_get_fields): for field in fields.values(): # Just access the attributes [ - field.fieldType, + field.field_type, field.parent, field.kids, field.name, - field.altName, - field.mappingName, + field.alternate_name, + field.mapping_name, field.flags, field.value, - field.defaultValue, - field.additionalActions, + field.default_value, + field.additional_actions, ] @@ -336,7 +342,7 @@ def test_get_page_number(src, page_nb): def test_get_page_layout(src, expected): src = os.path.join(RESOURCE_ROOT, src) reader = PdfReader(src) - assert reader.getPageLayout() == expected + assert reader.page_layout == expected @pytest.mark.parametrize( @@ -403,7 +409,8 @@ def test_read_prev_0_trailer(): ) pdf_stream = io.BytesIO(pdf_data) with pytest.raises(PdfReadError) as exc: - PdfReader(pdf_stream, strict=True) + with pytest.warns(PdfReadWarning): + PdfReader(pdf_stream, strict=True) assert exc.value.args[0] == "/Prev=0 in the trailer (try opening with strict=False)" @@ -473,14 +480,18 @@ def test_read_unknown_zero_pages(): pdf_data.find(b"xref") - 1, ) pdf_stream = io.BytesIO(pdf_data) - reader = PdfReader(pdf_stream, strict=True) + with pytest.warns(PdfReadWarning): + reader = PdfReader(pdf_stream, strict=True) with pytest.raises(PdfReadError) as exc: - len(reader.pages) + with pytest.warns(PdfReadWarning): + len(reader.pages) assert exc.value.args[0] == "Could not find object." - reader = PdfReader(pdf_stream, strict=False) + with pytest.warns(PdfReadWarning): + reader = PdfReader(pdf_stream, strict=False) with pytest.raises(AttributeError) as exc: - len(reader.pages) + with pytest.warns(PdfReadWarning): + len(reader.pages) assert exc.value.args[0] == "'NoneType' object has no attribute 'get_object'" @@ -495,7 +506,7 @@ def test_read_encrypted_without_decryption(): def test_get_destination_page_number(): src = os.path.join(RESOURCE_ROOT, "pdflatex-outline.pdf") reader = PdfReader(src) - outlines = reader.get_outlines() + outlines = reader._get_outlines() for outline in outlines: if not isinstance(outline, list): reader.get_destination_page_number(outline) @@ -543,27 +554,27 @@ def test_reader_properties(): [(True), (False)], ) def test_issue604(strict): - """ - Test with invalid destinations - """ + """Test with invalid destinations""" # todo with open(os.path.join(RESOURCE_ROOT, "issue-604.pdf"), "rb") as f: pdf = None bookmarks = None if strict: with pytest.raises(PdfReadError) as exc: pdf = PdfReader(f, strict=strict) - bookmarks = pdf.get_outlines() + with pytest.warns(PdfReadWarning): + bookmarks = pdf._get_outlines() if "Unknown Destination" not in exc.value.args[0]: raise Exception("Expected exception not raised") return # bookmarks not correct else: pdf = PdfReader(f, strict=strict) - bookmarks = pdf.get_outlines() + with pytest.warns(PdfReadWarning): + bookmarks = pdf._get_outlines() - def getDestPages(x): + def get_dest_pages(x): # print(x) if isinstance(x, list): - r = [getDestPages(y) for y in x] + r = [get_dest_pages(y) for y in x] return r else: return pdf.get_destination_page_number(x) + 1 @@ -572,7 +583,7 @@ def getDestPages(x): for ( b ) in bookmarks: # b can be destination or a list:preferred to just print them - out.append(getDestPages(b)) + out.append(get_dest_pages(b)) # print(out) @@ -607,7 +618,7 @@ def test_VirtualList(): def test_convert_to_int(): - assert convert_to_int(b'\x01', 8) == 1 + assert convert_to_int(b"\x01", 8) == 1 def test_convert_to_int_error(): @@ -617,5 +628,8 @@ def test_convert_to_int_error(): def test_convertToInt_deprecated(): - with pytest.warns(PendingDeprecationWarning, match="convertToInt will be removed with PyPDF2 2.0.0. Use convert_to_int instead."): - assert convertToInt(b'\x01', 8) == 1 + with pytest.warns( + PendingDeprecationWarning, + match="convertToInt will be removed with PyPDF2 2.0.0. Use convert_to_int instead.", + ): + assert convertToInt(b"\x01", 8) == 1 diff --git a/tests/test_workflows.py b/tests/test_workflows.py index cdfa0b5cf..98622a607 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -57,7 +57,7 @@ def test_PdfReaderJpegImage(): page = reader.pages[0] x_object = page[PG.RESOURCES]["/XObject"].get_object() - data = x_object["/Im4"].getData() + data = x_object["/Im4"].get_data() # Compare the text of the PDF to a known source assert binascii.hexlify(data).decode() == imagetext, ( @@ -90,7 +90,8 @@ def test_rotate(degree): with open(os.path.join(RESOURCE_ROOT, "crazyones.pdf"), "rb") as inputfile: reader = PdfReader(inputfile) page = reader.pages[0] - page.rotateCounterClockwise(degree) + with pytest.warns(PendingDeprecationWarning): + page.rotateCounterClockwise(degree) def test_rotate_45(): @@ -98,5 +99,6 @@ def test_rotate_45(): reader = PdfReader(inputfile) page = reader.pages[0] with pytest.raises(ValueError) as exc: - page.rotateCounterClockwise(45) + with pytest.warns(PendingDeprecationWarning): + page.rotateCounterClockwise(45) assert exc.value.args[0] == "Rotation angle must be a multiple of 90" diff --git a/tests/test_writer.py b/tests/test_writer.py index a90115375..4a581645e 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -354,10 +354,10 @@ def test_regression_issue670(): filepath = os.path.join(RESOURCE_ROOT, "crazyones.pdf") reader = PdfReader(filepath, strict=False) for _ in range(2): - pdf_writer = PdfWriter() - pdf_writer.add_page(reader.pages[0]) + writer = PdfWriter() + writer.add_page(reader.pages[0]) with open("dont_commit_issue670.pdf", "wb") as f_pdf: - pdf_writer.write(f_pdf) + writer.write(f_pdf) def test_issue301(): @@ -365,8 +365,8 @@ def test_issue301(): Test with invalid stream length object """ with open(os.path.join(RESOURCE_ROOT, "issue-301.pdf"), "rb") as f: - r = PdfReader(f) - w = PdfWriter() - w.append_pages_from_reader(r) + reader = PdfReader(f) + writer = PdfWriter() + writer.append_pages_from_reader(reader) o = BytesIO() - w.write(o) + writer.write(o) diff --git a/tests/test_xmp.py b/tests/test_xmp.py index 80770d986..fdd80a406 100644 --- a/tests/test_xmp.py +++ b/tests/test_xmp.py @@ -19,11 +19,11 @@ ) def test_read_xmp(src, has_xmp): reader = PdfReader(src) - xmp = reader.xmpMetadata + xmp = reader.xmp_metadata assert (xmp is None) == (not has_xmp) if has_xmp: - for el in xmp.getElement( - aboutUri="", namespace=PyPDF2.xmp.RDF_NAMESPACE, name="Artist" + for el in xmp.get_element( + about_uri="", namespace=PyPDF2.xmp.RDF_NAMESPACE, name="Artist" ): print(f"el={el}") @@ -33,9 +33,10 @@ def test_read_xmp(src, has_xmp): def get_all_tiff(xmp): data = {} - tiff_ns = xmp.getNodesInNamespace( - aboutUri="", namespace="http://ns.adobe.com/tiff/1.0/" - ) + with pytest.warns(PendingDeprecationWarning): + tiff_ns = xmp.getNodesInNamespace( + aboutUri="", namespace="http://ns.adobe.com/tiff/1.0/" + ) for tag in tiff_ns: contents = [] for content in tag.childNodes: