diff --git a/PyPDF2/_merger.py b/PyPDF2/_merger.py index 33e8725bf..4d7a659d8 100644 --- a/PyPDF2/_merger.py +++ b/PyPDF2/_merger.py @@ -46,8 +46,8 @@ from ._reader import PdfReader from ._utils import ( StrByteType, - deprecate_bookmark, - deprecate_with_replacement, + deprecation_bookmark, + deprecation_with_replacement, str_, ) from ._writer import PdfWriter @@ -102,7 +102,7 @@ class PdfMerger: file-like object. """ - @deprecate_bookmark(bookmarks="outline") + @deprecation_bookmark(bookmarks="outline") def __init__( self, strict: bool = False, fileobj: Union[Path, StrByteType] = "" ) -> None: @@ -130,7 +130,7 @@ def __exit__( self.write(self.fileobj) self.close() - @deprecate_bookmark(bookmark="outline_item", import_bookmarks="import_outline") + @deprecation_bookmark(bookmark="outline_item", import_bookmarks="import_outline") def merge( self, page_number: Optional[int] = None, @@ -171,9 +171,11 @@ def merge( old_term = "position" new_term = "page_number" warnings.warn( - message=( - f"{old_term} is deprecated as an argument. Use {new_term} instead" - ) + ( + f"{old_term} is deprecated as an argument and will be " + f"removed in PyPDF2=4.0.0. Use {new_term} instead" + ), + DeprecationWarning, ) else: raise ValueError( @@ -281,7 +283,7 @@ def _create_stream( ) return stream, encryption_obj - @deprecate_bookmark(bookmark="outline_item", import_bookmarks="import_outline") + @deprecation_bookmark(bookmark="outline_item", import_bookmarks="import_outline") def append( self, fileobj: Union[StrByteType, PdfReader, Path], @@ -375,7 +377,7 @@ def addMetadata(self, infos: Dict[str, Any]) -> None: # pragma: no cover Use :meth:`add_metadata` instead. """ - deprecate_with_replacement("addMetadata", "add_metadata") + deprecation_with_replacement("addMetadata", "add_metadata") self.add_metadata(infos) def setPageLayout(self, layout: LayoutType) -> None: # pragma: no cover @@ -384,7 +386,7 @@ def setPageLayout(self, layout: LayoutType) -> None: # pragma: no cover Use :meth:`set_page_layout` instead. """ - deprecate_with_replacement("setPageLayout", "set_page_layout") + deprecation_with_replacement("setPageLayout", "set_page_layout") self.set_page_layout(layout) def set_page_layout(self, layout: LayoutType) -> None: @@ -421,7 +423,7 @@ def setPageMode(self, mode: PagemodeType) -> None: # pragma: no cover Use :meth:`set_page_mode` instead. """ - deprecate_with_replacement("setPageMode", "set_page_mode") + deprecation_with_replacement("setPageMode", "set_page_mode", "3.0.0") self.set_page_mode(mode) def set_page_mode(self, mode: PagemodeType) -> None: @@ -513,7 +515,7 @@ def _write_dests(self) -> None: if pageno is not None: self.output.add_named_destination_object(named_dest) - @deprecate_bookmark(bookmarks="outline") + @deprecation_bookmark(bookmarks="outline") def _write_outline( self, outline: Optional[Iterable[OutlineItem]] = None, @@ -541,7 +543,7 @@ def _write_outline( del outline_item["/Page"], outline_item["/Type"] last_added = self.output.add_outline_item_dict(outline_item, parent) - @deprecate_bookmark(bookmark="outline_item") + @deprecation_bookmark(bookmark="outline_item") def _write_outline_item_on_page( self, outline_item: Union[OutlineItem, Destination], page: _MergedPage ) -> None: @@ -594,7 +596,7 @@ def _associate_dests_to_pages(self, pages: List[_MergedPage]) -> None: ) named_dest[NameObject("/Page")] = NumberObject(pageno) - @deprecate_bookmark(bookmarks="outline") + @deprecation_bookmark(bookmarks="outline") def _associate_outline_items_to_pages( self, pages: List[_MergedPage], outline: Optional[Iterable[OutlineItem]] = None ) -> None: @@ -619,7 +621,7 @@ def _associate_outline_items_to_pages( if pageno is not None: outline_item[NameObject("/Page")] = NumberObject(pageno) - @deprecate_bookmark(bookmark="outline_item") + @deprecation_bookmark(bookmark="outline_item") def find_outline_item( self, outline_item: Dict[str, Any], @@ -644,7 +646,7 @@ def find_outline_item( return None - @deprecate_bookmark(bookmark="outline_item") + @deprecation_bookmark(bookmark="outline_item") def find_bookmark( self, outline_item: Dict[str, Any], @@ -688,9 +690,11 @@ def add_outline_item( old_term = "pagenum" new_term = "page_number" warnings.warn( - message=( - f"{old_term} is deprecated as an argument. Use {new_term} instead" - ) + ( + f"{old_term} is deprecated as an argument and will be " + f"removed in PyPDF2==4.0.0. Use {new_term} instead" + ), + DeprecationWarning, ) page_number = pagenum if page_number is None: @@ -724,7 +728,7 @@ def addBookmark( .. deprecated:: 1.28.0 Use :meth:`add_outline_item` instead. """ - deprecate_with_replacement("addBookmark", "add_outline_item") + deprecation_with_replacement("addBookmark", "add_outline_item", "3.0.0") return self.add_outline_item( title, pagenum, @@ -750,7 +754,7 @@ def add_bookmark( .. deprecated:: 2.9.0 Use :meth:`add_outline_item` instead. """ - deprecate_with_replacement("addBookmark", "add_outline_item") + deprecation_with_replacement("addBookmark", "add_outline_item", "3.0.0") return self.add_outline_item( title, pagenum, @@ -766,7 +770,9 @@ def addNamedDestination(self, title: str, pagenum: int) -> None: # pragma: no c .. deprecated:: 1.28.0 Use :meth:`add_named_destination` instead. """ - deprecate_with_replacement("addNamedDestination", "add_named_destination") + deprecation_with_replacement( + "addNamedDestination", "add_named_destination", "3.0.0" + ) return self.add_named_destination(title, pagenum) def add_named_destination( @@ -789,9 +795,11 @@ def add_named_destination( old_term = "pagenum" new_term = "page_number" warnings.warn( - message=( - f"{old_term} is deprecated as an argument. Use {new_term} instead" - ) + ( + f"{old_term} is deprecated as an argument and will be " + f"removed in PyPDF2==4.0.0. Use {new_term} instead" + ), + DeprecationWarning, ) page_number = pagenum if page_number is None: @@ -806,7 +814,7 @@ def add_named_destination( class PdfFileMerger(PdfMerger): # pragma: no cover def __init__(self, *args: Any, **kwargs: Any) -> None: - deprecate_with_replacement("PdfFileMerger", "PdfMerger") + deprecation_with_replacement("PdfFileMerger", "PdfMerger", "3.0.0") if "strict" not in kwargs and len(args) < 1: kwargs["strict"] = True # maintain the default diff --git a/PyPDF2/_page.py b/PyPDF2/_page.py index 0b7688364..ed385bb3d 100644 --- a/PyPDF2/_page.py +++ b/PyPDF2/_page.py @@ -51,8 +51,8 @@ CompressedTransformationMatrix, File, TransformationMatrixType, - deprecate_no_replacement, - deprecate_with_replacement, + deprecation_no_replacement, + deprecation_with_replacement, logger_warning, matrix_multiply, ) @@ -73,7 +73,6 @@ NullObject, NumberObject, RectangleObject, - TextStringObject, encode_pdfdocencoding, ) @@ -143,7 +142,7 @@ def _get_rectangle(self: Any, name: str, defaults: Iterable[str]) -> RectangleOb def getRectangle( self: Any, name: str, defaults: Iterable[str] ) -> RectangleObject: # pragma: no cover - deprecate_no_replacement("getRectangle") + deprecation_no_replacement("getRectangle", "3.0.0") return _get_rectangle(self, name, defaults) @@ -155,7 +154,7 @@ def _set_rectangle(self: Any, name: str, value: Union[RectangleObject, float]) - def setRectangle( self: Any, name: str, value: Union[RectangleObject, float] ) -> None: # pragma: no cover - deprecate_no_replacement("setRectangle") + deprecation_no_replacement("setRectangle", "3.0.0") _set_rectangle(self, name, value) @@ -164,7 +163,7 @@ def _delete_rectangle(self: Any, name: str) -> None: def deleteRectangle(self: Any, name: str) -> None: # pragma: no cover - deprecate_no_replacement("deleteRectangle") + deprecation_no_replacement("deleteRectangle", "3.0.0") del self[name] @@ -179,7 +178,7 @@ def _create_rectangle_accessor(name: str, fallback: Iterable[str]) -> property: def createRectangleAccessor( name: str, fallback: Iterable[str] ) -> property: # pragma: no cover - deprecate_no_replacement("createRectangleAccessor") + deprecation_no_replacement("createRectangleAccessor", "3.0.0") return _create_rectangle_accessor(name, fallback) @@ -354,14 +353,18 @@ def __init__( self, pdf: Optional[PdfReaderProtocol] = None, indirect_reference: Optional[IndirectObject] = None, - indirect_ref: Optional[IndirectObject] = None, + indirect_ref: Optional[IndirectObject] = None, # deprecated ) -> None: DictionaryObject.__init__(self) self.pdf: Optional[PdfReaderProtocol] = pdf if indirect_ref is not None: # deprecated warnings.warn( - "Use indirect_reference instead of indirect_ref.", DeprecationWarning + ( + "indirect_ref is deprecated and will be removed in " + "PyPDF2 4.0.0. Use indirect_reference instead of indirect_ref." + ), + DeprecationWarning, ) if indirect_reference is not None: raise ValueError("Use indirect_reference instead of indirect_ref.") @@ -371,7 +374,11 @@ def __init__( @property def indirect_ref(self) -> Optional[IndirectObject]: # deprecated warnings.warn( - "Use indirect_reference instead of indirect_ref.", DeprecationWarning + ( + "indirect_ref is deprecated and will be removed in PyPDF2 4.0.0" + "Use indirect_reference instead of indirect_ref." + ), + DeprecationWarning, ) return self.indirect_reference @@ -451,7 +458,7 @@ def createBlankPage( Use :meth:`create_blank_page` instead. """ - deprecate_with_replacement("createBlankPage", "create_blank_page") + deprecation_with_replacement("createBlankPage", "create_blank_page", "3.0.0") return PageObject.create_blank_page(pdf, width, height) @property @@ -542,7 +549,7 @@ def rotate(self, angle: int) -> "PageObject": return self def rotate_clockwise(self, angle: int) -> "PageObject": # pragma: no cover - deprecate_with_replacement("rotate_clockwise", "rotate") + deprecation_with_replacement("rotate_clockwise", "rotate", "3.0.0") return self.rotate(angle) def rotateClockwise(self, angle: int) -> "PageObject": # pragma: no cover @@ -551,7 +558,7 @@ def rotateClockwise(self, angle: int) -> "PageObject": # pragma: no cover Use :meth:`rotate_clockwise` instead. """ - deprecate_with_replacement("rotateClockwise", "rotate") + deprecation_with_replacement("rotateClockwise", "rotate", "3.0.0") return self.rotate(angle) def rotateCounterClockwise(self, angle: int) -> "PageObject": # pragma: no cover @@ -560,7 +567,7 @@ def rotateCounterClockwise(self, angle: int) -> "PageObject": # pragma: no cove Use :meth:`rotate_clockwise` with a negative argument instead. """ - deprecate_with_replacement("rotateCounterClockwise", "rotate") + deprecation_with_replacement("rotateCounterClockwise", "rotate", "3.0.0") return self.rotate(-angle) @staticmethod @@ -656,7 +663,7 @@ def getContents(self) -> Optional[ContentStream]: # pragma: no cover Use :meth:`get_contents` instead. """ - deprecate_with_replacement("getContents", "get_contents") + deprecation_with_replacement("getContents", "get_contents", "3.0.0") return self.get_contents() def merge_page(self, page2: "PageObject", expand: bool = False) -> None: @@ -683,7 +690,7 @@ def mergePage(self, page2: "PageObject") -> None: # pragma: no cover Use :meth:`merge_page` instead. """ - deprecate_with_replacement("mergePage", "merge_page") + deprecation_with_replacement("mergePage", "merge_page", "3.0.0") return self.merge_page(page2) def _merge_page( @@ -850,9 +857,10 @@ def mergeTransformedPage( Use :meth:`add_transformation` and :meth:`merge_page` instead. """ - deprecate_with_replacement( + deprecation_with_replacement( "page.mergeTransformedPage(page2, ctm)", "page2.add_transformation(ctm); page.merge_page(page2)", + "3.0.0", ) if isinstance(ctm, Transformation): ctm = ctm.ctm @@ -883,9 +891,10 @@ def mergeScaledPage( Use :meth:`add_transformation` and :meth:`merge_page` instead. """ - deprecate_with_replacement( + deprecation_with_replacement( "page.mergeScaledPage(page2, scale, expand)", "page2.add_transformation(Transformation().scale(scale)); page.merge_page(page2, expand)", + "3.0.0", ) op = Transformation().scale(scale, scale) self.mergeTransformedPage(page2, op, expand) @@ -907,9 +916,10 @@ def mergeRotatedPage( Use :meth:`add_transformation` and :meth:`merge_page` instead. """ - deprecate_with_replacement( + deprecation_with_replacement( "page.mergeRotatedPage(page2, rotation, expand)", "page2.add_transformation(Transformation().rotate(rotation)); page.merge_page(page2, expand)", + "3.0.0", ) op = Transformation().rotate(rotation) self.mergeTransformedPage(page2, op, expand) @@ -932,9 +942,10 @@ def mergeTranslatedPage( Use :meth:`add_transformation` and :meth:`merge_page` instead. """ - deprecate_with_replacement( + deprecation_with_replacement( "page.mergeTranslatedPage(page2, tx, ty, expand)", "page2.add_transformation(Transformation().translate(tx, ty)); page.merge_page(page2, expand)", + "3.0.0", ) op = Transformation().translate(tx, ty) self.mergeTransformedPage(page2, op, expand) @@ -963,9 +974,10 @@ def mergeRotatedTranslatedPage( Use :meth:`add_transformation` and :meth:`merge_page` instead. """ - deprecate_with_replacement( + deprecation_with_replacement( "page.mergeRotatedTranslatedPage(page2, rotation, tx, ty, expand)", "page2.add_transformation(Transformation().rotate(rotation).translate(tx, ty)); page.merge_page(page2, expand)", + "3.0.0", ) op = Transformation().translate(-tx, -ty).rotate(rotation).translate(tx, ty) return self.mergeTransformedPage(page2, op, expand) @@ -988,9 +1000,10 @@ def mergeRotatedScaledPage( Use :meth:`add_transformation` and :meth:`merge_page` instead. """ - deprecate_with_replacement( + deprecation_with_replacement( "page.mergeRotatedScaledPage(page2, rotation, scale, expand)", "page2.add_transformation(Transformation().rotate(rotation).scale(scale)); page.merge_page(page2, expand)", + "3.0.0", ) op = Transformation().rotate(rotation).scale(scale, scale) self.mergeTransformedPage(page2, op, expand) @@ -1019,9 +1032,10 @@ def mergeScaledTranslatedPage( Use :meth:`add_transformation` and :meth:`merge_page` instead. """ - deprecate_with_replacement( + deprecation_with_replacement( "page.mergeScaledTranslatedPage(page2, scale, tx, ty, expand)", "page2.add_transformation(Transformation().scale(scale).translate(tx, ty)); page.merge_page(page2, expand)", + "3.0.0", ) op = Transformation().scale(scale, scale).translate(tx, ty) return self.mergeTransformedPage(page2, op, expand) @@ -1053,9 +1067,10 @@ def mergeRotatedScaledTranslatedPage( Use :meth:`add_transformation` and :meth:`merge_page` instead. """ - deprecate_with_replacement( + deprecation_with_replacement( "page.mergeRotatedScaledTranslatedPage(page2, rotation, tx, ty, expand)", "page2.add_transformation(Transformation().rotate(rotation).scale(scale)); page.merge_page(page2, expand)", + "3.0.0", ) op = Transformation().rotate(rotation).scale(scale, scale).translate(tx, ty) self.mergeTransformedPage(page2, op, expand) @@ -1125,7 +1140,7 @@ def addTransformation( Use :meth:`add_transformation` instead. """ - deprecate_with_replacement("addTransformation", "add_transformation") + deprecation_with_replacement("addTransformation", "add_transformation", "3.0.0") self.add_transformation(ctm) def scale(self, sx: float, sy: float) -> None: @@ -1197,7 +1212,7 @@ def scaleBy(self, factor: float) -> None: # pragma: no cover Use :meth:`scale_by` instead. """ - deprecate_with_replacement("scaleBy", "scale_by") + deprecation_with_replacement("scaleBy", "scale_by", "3.0.0") self.scale(factor, factor) def scale_to(self, width: float, height: float) -> None: @@ -1219,7 +1234,7 @@ def scaleTo(self, width: float, height: float) -> None: # pragma: no cover Use :meth:`scale_to` instead. """ - deprecate_with_replacement("scaleTo", "scale_to") + deprecation_with_replacement("scaleTo", "scale_to", "3.0.0") self.scale_to(width, height) def compress_content_streams(self) -> None: @@ -1242,87 +1257,11 @@ def compressContentStreams(self) -> None: # pragma: no cover Use :meth:`compress_content_streams` instead. """ - deprecate_with_replacement("compressContentStreams", "compress_content_streams") + deprecation_with_replacement( + "compressContentStreams", "compress_content_streams", "3.0.0" + ) self.compress_content_streams() - def _extract_text_old( - self, Tj_sep: str = "", TJ_sep: str = "" - ) -> str: # pragma: no cover - """ - Locate all text drawing commands, in the order they are provided in the - content stream, and extract the text. This works well for some PDF - files, but poorly for others, depending on the generator used. This will - be refined in the future. Do not rely on the order of text coming out of - this function, as it will change if this function is made more - sophisticated. - - :return: a string object. - """ - text = "" - content = self[PG.CONTENTS].get_object() - if not isinstance(content, ContentStream): - content = ContentStream(content, self.pdf) - # Note: we check all strings are TextStringObjects. ByteStringObjects - # are strings where the byte->string encoding was unknown, so adding - # them to the text here would be gibberish. - - space_scale = 1.0 - - for operands, operator in content.operations: - # Missing operators: - # Tf: text font - # Tfs: text font size - # Tc: '5.2.1 Character Spacing' - # Th: '5.2.3 Horizontal Scaling' - # Tl: '5.2.4 Leading' - # Tmode: '5.2.5 Text Rendering Mode' - # Trise: '5.2.6 Text Rise' - - if operator in [b"Tf", b"Tfs", b"Tc", b"Th", b"Tl", b"Tmode"]: - pass - elif operator == b"Tw": # word spacing - # See '5.2.2 Word Spacing' - space_scale = 1.0 + float(operands[0]) - elif operator == b"Tj": - # See 'TABLE 5.6 Text-showing operators' - _text = operands[0] - if isinstance(_text, TextStringObject): - text += Tj_sep - text += _text - text += "\n" - elif operator == b"T*": - # See 'TABLE 5.5 Text-positioning operators' - text += "\n" - elif operator == b"'": - # See 'TABLE 5.6 Text-showing operators' - text += "\n" - _text = operands[0] - if isinstance(_text, TextStringObject): - text += operands[0] - elif operator == b'"': - # See 'TABLE 5.6 Text-showing operators' - _text = operands[2] - if isinstance(_text, TextStringObject): - text += "\n" - text += _text - elif operator == b"TJ": - # See 'TABLE 5.6 Text-showing operators' - for i in operands[0]: - if isinstance(i, TextStringObject): - text += TJ_sep - text += i - elif isinstance(i, (NumberObject, FloatObject)): - # a positive value decreases and the negative value increases - # space - if int(i) < -space_scale * 250: - if len(text) == 0 or text[-1] != " ": - text += " " - else: - if len(text) > 1 and text[-1] == " ": - text = text[:-1] - text += "\n" - return text - def _debug_for_extract(self) -> str: # pragma: no cover out = "" for ope, op in ContentStream( @@ -1850,8 +1789,8 @@ def extract_text( For example in some PDF files this can be useful to parse tables. Args: - Tj_sep: Deprecated. Kept for compatibility until PyPDF2==4.0.0 - TJ_sep: Deprecated. Kept for compatibility until PyPDF2==4.0.0 + Tj_sep: Deprecated. Kept for compatibility until PyPDF2 4.0.0 + TJ_sep: Deprecated. Kept for compatibility until PyPDF2 4.0.0 orientations: list of orientations text_extraction will look for default = (0, 90, 180, 270) note: currently only 0(Up),90(turned Left), 180(upside Down), @@ -1902,7 +1841,7 @@ def extract_text( raise TypeError(f"Invalid positional parameter {args[0]}") if Tj_sep is not None or TJ_sep is not None: warnings.warn( - "parameters Tj_Sep, TJ_sep depreciated, and will be removed in PyPDF2 3.0.0.", + "parameters Tj_Sep, TJ_sep depreciated, and will be removed in PyPDF2 4.0.0.", DeprecationWarning, ) @@ -1957,7 +1896,7 @@ def extractText( Use :meth:`extract_text` instead. """ - deprecate_with_replacement("extractText", "extract_text") + deprecation_with_replacement("extractText", "extract_text", "3.0.0") return self.extract_text() def _get_fonts(self) -> Tuple[Set[str], Set[str]]: @@ -1986,7 +1925,7 @@ def mediaBox(self) -> RectangleObject: # pragma: no cover Use :py:attr:`mediabox` instead. """ - deprecate_with_replacement("mediaBox", "mediabox") + deprecation_with_replacement("mediaBox", "mediabox", "3.0.0") return self.mediabox @mediaBox.setter @@ -1996,7 +1935,7 @@ def mediaBox(self, value: RectangleObject) -> None: # pragma: no cover Use :py:attr:`mediabox` instead. """ - deprecate_with_replacement("mediaBox", "mediabox") + deprecation_with_replacement("mediaBox", "mediabox", "3.0.0") self.mediabox = value cropbox = _create_rectangle_accessor("/CropBox", (PG.MEDIABOX,)) @@ -2015,12 +1954,12 @@ def cropBox(self) -> RectangleObject: # pragma: no cover Use :py:attr:`cropbox` instead. """ - deprecate_with_replacement("cropBox", "cropbox") + deprecation_with_replacement("cropBox", "cropbox", "3.0.0") return self.cropbox @cropBox.setter def cropBox(self, value: RectangleObject) -> None: # pragma: no cover - deprecate_with_replacement("cropBox", "cropbox") + deprecation_with_replacement("cropBox", "cropbox", "3.0.0") self.cropbox = value bleedbox = _create_rectangle_accessor("/BleedBox", ("/CropBox", PG.MEDIABOX)) @@ -2037,12 +1976,12 @@ def bleedBox(self) -> RectangleObject: # pragma: no cover Use :py:attr:`bleedbox` instead. """ - deprecate_with_replacement("bleedBox", "bleedbox") + deprecation_with_replacement("bleedBox", "bleedbox", "3.0.0") return self.bleedbox @bleedBox.setter def bleedBox(self, value: RectangleObject) -> None: # pragma: no cover - deprecate_with_replacement("bleedBox", "bleedbox") + deprecation_with_replacement("bleedBox", "bleedbox", "3.0.0") self.bleedbox = value trimbox = _create_rectangle_accessor("/TrimBox", ("/CropBox", PG.MEDIABOX)) @@ -2058,12 +1997,12 @@ def trimBox(self) -> RectangleObject: # pragma: no cover Use :py:attr:`trimbox` instead. """ - deprecate_with_replacement("trimBox", "trimbox") + deprecation_with_replacement("trimBox", "trimbox", "3.0.0") return self.trimbox @trimBox.setter def trimBox(self, value: RectangleObject) -> None: # pragma: no cover - deprecate_with_replacement("trimBox", "trimbox") + deprecation_with_replacement("trimBox", "trimbox", "3.0.0") self.trimbox = value artbox = _create_rectangle_accessor("/ArtBox", ("/CropBox", PG.MEDIABOX)) @@ -2080,12 +2019,12 @@ def artBox(self) -> RectangleObject: # pragma: no cover Use :py:attr:`artbox` instead. """ - deprecate_with_replacement("artBox", "artbox") + deprecation_with_replacement("artBox", "artbox", "3.0.0") return self.artbox @artBox.setter def artBox(self, value: RectangleObject) -> None: # pragma: no cover - deprecate_with_replacement("artBox", "artbox") + deprecation_with_replacement("artBox", "artbox", "3.0.0") self.artbox = value @property diff --git a/PyPDF2/_reader.py b/PyPDF2/_reader.py index d7ccca91c..0a9144766 100644 --- a/PyPDF2/_reader.py +++ b/PyPDF2/_reader.py @@ -53,7 +53,8 @@ StreamType, b_, deprecate_no_replacement, - deprecate_with_replacement, + deprecation_no_replacement, + deprecation_with_replacement, logger_warning, read_non_whitespace, read_previous_line, @@ -111,7 +112,7 @@ def convert_to_int(d: bytes, size: int) -> Union[int, Tuple[Any, ...]]: def convertToInt( d: bytes, size: int ) -> Union[int, Tuple[Any, ...]]: # pragma: no cover - deprecate_with_replacement("convertToInt", "convert_to_int") + deprecation_with_replacement("convertToInt", "convert_to_int") return convert_to_int(d, size) @@ -146,7 +147,7 @@ def getText(self, key: str) -> Optional[str]: # pragma: no cover Use the attributes (e.g. :py:attr:`title` / :py:attr:`author`). """ - deprecate_no_replacement("getText") + deprecation_no_replacement("getText", "3.0.0") return self._get_text(key) @property @@ -382,7 +383,7 @@ def getDocumentInfo(self) -> Optional[DocumentInformation]: # pragma: no cover Use the attribute :py:attr:`metadata` instead. """ - deprecate_with_replacement("getDocumentInfo", "metadata") + deprecation_with_replacement("getDocumentInfo", "metadata", "3.0.0") return self.metadata @property @@ -392,7 +393,7 @@ def documentInfo(self) -> Optional[DocumentInformation]: # pragma: no cover Use the attribute :py:attr:`metadata` instead. """ - deprecate_with_replacement("documentInfo", "metadata") + deprecation_with_replacement("documentInfo", "metadata", "3.0.0") return self.metadata @property @@ -416,7 +417,7 @@ def getXmpMetadata(self) -> Optional[XmpInformation]: # pragma: no cover Use the attribute :py:attr:`xmp_metadata` instead. """ - deprecate_with_replacement("getXmpMetadata", "xmp_metadata") + deprecation_with_replacement("getXmpMetadata", "xmp_metadata", "3.0.0") return self.xmp_metadata @property @@ -426,7 +427,7 @@ def xmpMetadata(self) -> Optional[XmpInformation]: # pragma: no cover Use the attribute :py:attr:`xmp_metadata` instead. """ - deprecate_with_replacement("xmpMetadata", "xmp_metadata") + deprecation_with_replacement("xmpMetadata", "xmp_metadata", "3.0.0") return self.xmp_metadata def _get_num_pages(self) -> int: @@ -453,7 +454,7 @@ def getNumPages(self) -> int: # pragma: no cover Use :code:`len(reader.pages)` instead. """ - deprecate_with_replacement("reader.getNumPages", "len(reader.pages)") + deprecation_with_replacement("reader.getNumPages", "len(reader.pages)", "3.0.0") return self._get_num_pages() @property @@ -463,7 +464,7 @@ def numPages(self) -> int: # pragma: no cover Use :code:`len(reader.pages)` instead. """ - deprecate_with_replacement("reader.numPages", "len(reader.pages)") + deprecation_with_replacement("reader.numPages", "len(reader.pages)", "3.0.0") return self._get_num_pages() def getPage(self, pageNumber: int) -> PageObject: # pragma: no cover @@ -472,8 +473,8 @@ def getPage(self, pageNumber: int) -> PageObject: # pragma: no cover Use :code:`reader.pages[page_number]` instead. """ - deprecate_with_replacement( - "reader.getPage(pageNumber)", "reader.pages[page_number]" + deprecation_with_replacement( + "reader.getPage(pageNumber)", "reader.pages[page_number]", "3.0.0" ) return self._get_page(pageNumber) @@ -499,7 +500,7 @@ def namedDestinations(self) -> Dict[str, Any]: # pragma: no cover Use :py:attr:`named_destinations` instead. """ - deprecate_with_replacement("namedDestinations", "named_destinations") + deprecation_with_replacement("namedDestinations", "named_destinations", "3.0.0") return self.named_destinations @property @@ -569,7 +570,7 @@ def getFields( Use :meth:`get_fields` instead. """ - deprecate_with_replacement("getFields", "get_fields") + deprecation_with_replacement("getFields", "get_fields", "3.0.0") return self.get_fields(tree, retval, fileobj) def _build_field( @@ -664,7 +665,9 @@ def getFormTextFields(self) -> Dict[str, Any]: # pragma: no cover Use :meth:`get_form_text_fields` instead. """ - deprecate_with_replacement("getFormTextFields", "get_form_text_fields") + deprecation_with_replacement( + "getFormTextFields", "get_form_text_fields", "3.0.0" + ) return self.get_form_text_fields() def _get_named_destinations( @@ -726,7 +729,9 @@ def getNamedDestinations( Use :py:attr:`named_destinations` instead. """ - deprecate_with_replacement("getNamedDestinations", "named_destinations") + deprecation_with_replacement( + "getNamedDestinations", "named_destinations", "3.0.0" + ) return self._get_named_destinations(tree, retval) @property @@ -746,7 +751,7 @@ def outlines(self) -> OutlineType: # pragma: no cover Use :py:attr:`outline` instead. """ - deprecate_with_replacement("outlines", "outline") + deprecation_with_replacement("outlines", "outline", "3.0.0") return self.outline def _get_outline( @@ -798,7 +803,7 @@ def getOutlines( Use :py:attr:`outline` instead. """ - deprecate_with_replacement("getOutlines", "outline") + deprecation_with_replacement("getOutlines", "outline", "3.0.0") return self._get_outline(node, outline) @property @@ -850,7 +855,7 @@ def getPageNumber(self, page: PageObject) -> int: # pragma: no cover Use :meth:`get_page_number` instead. """ - deprecate_with_replacement("getPageNumber", "get_page_number") + deprecation_with_replacement("getPageNumber", "get_page_number", "3.0.0") return self.get_page_number(page) def get_destination_page_number(self, destination: Destination) -> int: @@ -870,8 +875,8 @@ def getDestinationPageNumber( Use :meth:`get_destination_page_number` instead. """ - deprecate_with_replacement( - "getDestinationPageNumber", "get_destination_page_number" + deprecation_with_replacement( + "getDestinationPageNumber", "get_destination_page_number", "3.0.0" ) return self.get_destination_page_number(destination) @@ -1016,7 +1021,7 @@ def getPageLayout(self) -> Optional[str]: # pragma: no cover Use :py:attr:`page_layout` instead. """ - deprecate_with_replacement("getPageLayout", "page_layout") + deprecation_with_replacement("getPageLayout", "page_layout", "3.0.0") return self.page_layout @property @@ -1026,7 +1031,7 @@ def pageLayout(self) -> Optional[str]: # pragma: no cover Use :py:attr:`page_layout` instead. """ - deprecate_with_replacement("pageLayout", "page_layout") + deprecation_with_replacement("pageLayout", "page_layout", "3.0.0") return self.page_layout @property @@ -1063,7 +1068,7 @@ def getPageMode(self) -> Optional[PagemodeType]: # pragma: no cover Use :py:attr:`page_mode` instead. """ - deprecate_with_replacement("getPageMode", "page_mode") + deprecation_with_replacement("getPageMode", "page_mode", "3.0.0") return self.page_mode @property @@ -1073,7 +1078,7 @@ def pageMode(self) -> Optional[PagemodeType]: # pragma: no cover Use :py:attr:`page_mode` instead. """ - deprecate_with_replacement("pageMode", "page_mode") + deprecation_with_replacement("pageMode", "page_mode", "3.0.0") return self.page_mode def _flatten( @@ -1321,7 +1326,7 @@ def getObject( Use :meth:`get_object` instead. """ - deprecate_with_replacement("getObject", "get_object") + deprecation_with_replacement("getObject", "get_object", "3.0.0") return self.get_object(indirectReference) def read_object_header(self, stream: StreamType) -> Tuple[int, int]: @@ -1360,7 +1365,7 @@ def readObjectHeader( Use :meth:`read_object_header` instead. """ - deprecate_with_replacement("readObjectHeader", "read_object_header") + deprecation_with_replacement("readObjectHeader", "read_object_header", "3.0.0") return self.read_object_header(stream) def cache_get_indirect_object( @@ -1376,8 +1381,8 @@ def cacheGetIndirectObject( Use :meth:`cache_get_indirect_object` instead. """ - deprecate_with_replacement( - "cacheGetIndirectObject", "cache_get_indirect_object" + deprecation_with_replacement( + "cacheGetIndirectObject", "cache_get_indirect_object", "3.0.0" ) return self.cache_get_indirect_object(generation, idnum) @@ -1402,7 +1407,7 @@ def cacheIndirectObject( Use :meth:`cache_indirect_object` instead. """ - deprecate_with_replacement("cacheIndirectObject", "cache_indirect_object") + deprecation_with_replacement("cacheIndirectObject", "cache_indirect_object") return self.cache_indirect_object(generation, idnum, obj) def read(self, stream: StreamType) -> None: @@ -1873,7 +1878,7 @@ def readNextEndLine( self, stream: StreamType, limit_offset: int = 0 ) -> bytes: # pragma: no cover """.. deprecated:: 1.28.0""" - deprecate_no_replacement("readNextEndLine") + deprecation_no_replacement("readNextEndLine", "3.0.0") return self.read_next_end_line(stream, limit_offset) def decrypt(self, password: Union[str, bytes]) -> PasswordType: @@ -1926,7 +1931,7 @@ def getIsEncrypted(self) -> bool: # pragma: no cover Use :py:attr:`is_encrypted` instead. """ - deprecate_with_replacement("getIsEncrypted", "is_encrypted") + deprecation_with_replacement("getIsEncrypted", "is_encrypted", "3.0.0") return self.is_encrypted @property @@ -1936,7 +1941,7 @@ def isEncrypted(self) -> bool: # pragma: no cover Use :py:attr:`is_encrypted` instead. """ - deprecate_with_replacement("isEncrypted", "is_encrypted") + deprecation_with_replacement("isEncrypted", "is_encrypted", "3.0.0") return self.is_encrypted @property @@ -1966,7 +1971,7 @@ def xfa(self) -> Optional[Dict[str, Any]]: class PdfFileReader(PdfReader): # pragma: no cover def __init__(self, *args: Any, **kwargs: Any) -> None: - deprecate_with_replacement("PdfFileReader", "PdfReader") + deprecation_with_replacement("PdfFileReader", "PdfReader", "3.0.0") if "strict" not in kwargs and len(args) < 2: kwargs["strict"] = True # maintain the default super().__init__(*args, **kwargs) diff --git a/PyPDF2/_utils.py b/PyPDF2/_utils.py index 947233919..b6f090b8d 100644 --- a/PyPDF2/_utils.py +++ b/PyPDF2/_utils.py @@ -54,7 +54,11 @@ except ImportError: from typing_extensions import TypeAlias -from .errors import STREAM_TRUNCATED_PREMATURELY, PdfStreamError +from .errors import ( + STREAM_TRUNCATED_PREMATURELY, + DeprecationError, + PdfStreamError, +) TransformationMatrixType: TypeAlias = Tuple[ Tuple[float, float, float], Tuple[float, float, float], Tuple[float, float, float] @@ -67,7 +71,9 @@ StrByteType = Union[str, StreamType] DEPR_MSG_NO_REPLACEMENT = "{} is deprecated and will be removed in PyPDF2 {}." +DEPR_MSG_NO_REPLACEMENT_HAPPENED = "{} is deprecated and was removed in PyPDF2 {}." DEPR_MSG = "{} is deprecated and will be removed in PyPDF2 3.0.0. Use {} instead." +DEPR_MSG_HAPPENED = "{} is deprecated and was removed in PyPDF2 {}. Use {} instead." def _get_max_pdf_version_header(header1: bytes, header2: bytes) -> bytes: @@ -338,19 +344,45 @@ def paeth_predictor(left: int, up: int, up_left: int) -> int: def deprecate(msg: str, stacklevel: int = 3) -> None: - warnings.warn(msg, PendingDeprecationWarning, stacklevel=stacklevel) + warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel) + + +def deprecation(msg: str) -> None: + raise DeprecationError(msg) def deprecate_with_replacement( old_name: str, new_name: str, removed_in: str = "3.0.0" ) -> None: + """ + Raise an exception that a feature will be removed, but has a replacement. + """ deprecate(DEPR_MSG.format(old_name, new_name, removed_in), 4) +def deprecation_with_replacement( + old_name: str, new_name: str, removed_in: str = "3.0.0" +) -> None: + """ + Raise an exception that a feature was already removed, but has a replacement. + """ + deprecation(DEPR_MSG_HAPPENED.format(old_name, removed_in, new_name)) + + def deprecate_no_replacement(name: str, removed_in: str = "3.0.0") -> None: + """ + Raise an exception that a feature will be removed without replacement. + """ deprecate(DEPR_MSG_NO_REPLACEMENT.format(name, removed_in), 4) +def deprecation_no_replacement(name: str, removed_in: str = "3.0.0") -> None: + """ + Raise an exception that a feature was already removed without replacement. + """ + deprecation(DEPR_MSG_NO_REPLACEMENT_HAPPENED.format(name, removed_in)) + + def logger_warning(msg: str, src: str) -> None: """ Use this instead of logger.warning directly. @@ -370,7 +402,7 @@ def logger_warning(msg: str, src: str) -> None: logging.getLogger(src).warning(msg) -def deprecate_bookmark(**aliases: str) -> Callable: +def deprecation_bookmark(**aliases: str) -> Callable: """ Decorator for deprecated term "bookmark" To be used for methods and function arguments @@ -381,7 +413,7 @@ def deprecate_bookmark(**aliases: str) -> Callable: def decoration(func: Callable): # type: ignore @functools.wraps(func) def wrapper(*args, **kwargs): # type: ignore - rename_kwargs(func.__name__, kwargs, aliases) + rename_kwargs(func.__name__, kwargs, aliases, fail=True) return func(*args, **kwargs) return wrapper @@ -390,7 +422,7 @@ def wrapper(*args, **kwargs): # type: ignore def rename_kwargs( # type: ignore - func_name: str, kwargs: Dict[str, Any], aliases: Dict[str, str] + func_name: str, kwargs: Dict[str, Any], aliases: Dict[str, str], fail: bool = False ): """ Helper function to deprecate arguments. @@ -398,6 +430,10 @@ def rename_kwargs( # type: ignore for old_term, new_term in aliases.items(): if old_term in kwargs: + if fail: + raise DeprecationError( + f"{old_term} is deprecated as an argument. Use {new_term} instead" + ) if new_term in kwargs: raise TypeError( f"{func_name} received both {old_term} and {new_term} as an argument. " @@ -407,7 +443,8 @@ def rename_kwargs( # type: ignore warnings.warn( message=( f"{old_term} is deprecated as an argument. Use {new_term} instead" - ) + ), + category=DeprecationWarning, ) diff --git a/PyPDF2/_writer.py b/PyPDF2/_writer.py index dcb5ffee0..b2e92cdb1 100644 --- a/PyPDF2/_writer.py +++ b/PyPDF2/_writer.py @@ -66,8 +66,9 @@ StreamType, _get_max_pdf_version_header, b_, - deprecate_bookmark, deprecate_with_replacement, + deprecation_bookmark, + deprecation_with_replacement, logger_warning, ) from .constants import AnnotationDictionaryAttributes @@ -225,7 +226,7 @@ def get_object( else: indirect_reference = ido warnings.warn( - "The parameter 'ido' is depreciated and will be removed in PyPDF2 3.0.0.", + "The parameter 'ido' is depreciated and will be removed in PyPDF2 4.0.0.", DeprecationWarning, ) assert ( @@ -245,7 +246,7 @@ def getObject( Use :meth:`get_object` instead. """ - deprecate_with_replacement("getObject", "get_object") + deprecation_with_replacement("getObject", "get_object", "3.0.0") return self.get_object(ido) def _add_page( @@ -329,7 +330,7 @@ def addPage( Use :meth:`add_page` instead. """ - deprecate_with_replacement("addPage", "add_page") + deprecation_with_replacement("addPage", "add_page", "3.0.0") return self.add_page(page, excluded_keys) def insert_page( @@ -358,7 +359,7 @@ def insertPage( Use :meth:`insert_page` instead. """ - deprecate_with_replacement("insertPage", "insert_page") + deprecation_with_replacement("insertPage", "insert_page", "3.0.0") return self.insert_page(page, index, excluded_keys) def get_page( @@ -390,7 +391,7 @@ def getPage(self, pageNumber: int) -> PageObject: # pragma: no cover Use :code:`writer.pages[page_number]` instead. """ - deprecate_with_replacement("getPage", "writer.pages[page_number]") + deprecation_with_replacement("getPage", "writer.pages[page_number]", "3.0.0") return self.get_page(pageNumber) def _get_num_pages(self) -> int: @@ -403,7 +404,7 @@ def getNumPages(self) -> int: # pragma: no cover Use :code:`len(writer.pages)` instead. """ - deprecate_with_replacement("getNumPages", "len(writer.pages)") + deprecation_with_replacement("getNumPages", "len(writer.pages)", "3.0.0") return self._get_num_pages() @property @@ -438,7 +439,7 @@ def addBlankPage( Use :meth:`add_blank_page` instead. """ - deprecate_with_replacement("addBlankPage", "add_blank_page") + deprecation_with_replacement("addBlankPage", "add_blank_page", "3.0.0") return self.add_blank_page(width, height) def insert_blank_page( @@ -479,7 +480,7 @@ def insertBlankPage( Use :meth:`insertBlankPage` instead. """ - deprecate_with_replacement("insertBlankPage", "insert_blank_page") + deprecation_with_replacement("insertBlankPage", "insert_blank_page", "3.0.0") return self.insert_blank_page(width, height, index) @property @@ -573,7 +574,7 @@ def addJS(self, javascript: str) -> None: # pragma: no cover Use :meth:`add_js` instead. """ - deprecate_with_replacement("addJS", "add_js") + deprecation_with_replacement("addJS", "add_js", "3.0.0") return self.add_js(javascript) def add_attachment(self, filename: str, data: Union[str, bytes]) -> None: @@ -666,7 +667,7 @@ def addAttachment( Use :meth:`add_attachment` instead. """ - deprecate_with_replacement("addAttachment", "add_attachment") + deprecation_with_replacement("addAttachment", "add_attachment", "3.0.0") return self.add_attachment(fname, fdata) def append_pages_from_reader( @@ -707,7 +708,9 @@ def appendPagesFromReader( Use :meth:`append_pages_from_reader` instead. """ - deprecate_with_replacement("appendPagesFromReader", "append_pages_from_reader") + deprecation_with_replacement( + "appendPagesFromReader", "append_pages_from_reader", "3.0.0" + ) self.append_pages_from_reader(reader, after_page_append) def update_page_form_field_values( @@ -786,8 +789,8 @@ def updatePageFormFieldValues( Use :meth:`update_page_form_field_values` instead. """ - deprecate_with_replacement( - "updatePageFormFieldValues", "update_page_form_field_values" + deprecation_with_replacement( + "updatePageFormFieldValues", "update_page_form_field_values", "3.0.0" ) return self.update_page_form_field_values(page, fields, flags) @@ -805,8 +808,8 @@ def cloneReaderDocumentRoot(self, reader: PdfReader) -> None: # pragma: no cove Use :meth:`clone_reader_document_root` instead. """ - deprecate_with_replacement( - "cloneReaderDocumentRoot", "clone_reader_document_root" + deprecation_with_replacement( + "cloneReaderDocumentRoot", "clone_reader_document_root", "3.0.0" ) self.clone_reader_document_root(reader) @@ -840,8 +843,8 @@ def cloneDocumentFromReader( Use :meth:`clone_document_from_reader` instead. """ - deprecate_with_replacement( - "cloneDocumentFromReader", "clone_document_from_reader" + deprecation_with_replacement( + "cloneDocumentFromReader", "clone_document_from_reader", "3.0.0" ) self.clone_document_from_reader(reader, after_page_append) @@ -882,8 +885,8 @@ def encrypt( else: warnings.warn( "Please use 'user_password' instead of 'user_pwd'. " - "The 'user_pwd' argument is deprecated and will be removed " - "in PyPDF2==3.0.0." + "The 'user_pwd' argument is deprecated and " + "will be removed in PyPDF2 4.0.0." ) user_password = user_pwd if user_password is None: # deprecated @@ -900,8 +903,10 @@ def encrypt( new_term = "owner_password" warnings.warn( message=( - f"{old_term} is deprecated as an argument. Use {new_term} instead" - ) + f"{old_term} is deprecated as an argument and will be " + f"removed in PyPDF2 4.0.0. Use {new_term} instead" + ), + category=DeprecationWarning, ) owner_password = owner_pwd @@ -1055,7 +1060,7 @@ def addMetadata(self, infos: Dict[str, Any]) -> None: # pragma: no cover Use :meth:`add_metadata` instead. """ - deprecate_with_replacement("addMetadata", "add_metadata") + deprecation_with_replacement("addMetadata", "add_metadata", "3.0.0") self.add_metadata(infos) def _sweep_indirect_references( @@ -1189,7 +1194,7 @@ def getReference(self, obj: PdfObject) -> IndirectObject: # pragma: no cover Use :meth:`get_reference` instead. """ - deprecate_with_replacement("getReference", "get_reference") + deprecation_with_replacement("getReference", "get_reference", "3.0.0") return self.get_reference(obj) def get_outline_root(self) -> TreeObject: @@ -1236,7 +1241,7 @@ def getOutlineRoot(self) -> TreeObject: # pragma: no cover Use :meth:`get_outline_root` instead. """ - deprecate_with_replacement("getOutlineRoot", "get_outline_root") + deprecation_with_replacement("getOutlineRoot", "get_outline_root", "3.0.0") return self.get_outline_root() def get_named_dest_root(self) -> ArrayObject: @@ -1280,7 +1285,7 @@ def getNamedDestRoot(self) -> ArrayObject: # pragma: no cover Use :meth:`get_named_dest_root` instead. """ - deprecate_with_replacement("getNamedDestRoot", "get_named_dest_root") + deprecation_with_replacement("getNamedDestRoot", "get_named_dest_root", "3.0.0") return self.get_named_dest_root() def add_outline_item_destination( @@ -1299,8 +1304,10 @@ def add_outline_item_destination( new_term = "page_destination" warnings.warn( message=( - f"{old_term} is deprecated as an argument. Use {new_term} instead" - ) + f"{old_term} is deprecated as an argument and will be " + f"removed in PyPDF2 4.0.0. Use {new_term} instead" + ), + category=DeprecationWarning, ) page_destination = dest if page_destination is None: # deprecated @@ -1328,8 +1335,8 @@ def add_bookmark_destination( Use :meth:`add_outline_item_destination` instead. """ - deprecate_with_replacement( - "add_bookmark_destination", "add_outline_item_destination" + deprecation_with_replacement( + "add_bookmark_destination", "add_outline_item_destination", "3.0.0" ) return self.add_outline_item_destination(dest, parent) @@ -1341,12 +1348,12 @@ def addBookmarkDestination( Use :meth:`add_outline_item_destination` instead. """ - deprecate_with_replacement( - "addBookmarkDestination", "add_outline_item_destination" + deprecation_with_replacement( + "addBookmarkDestination", "add_outline_item_destination", "3.0.0" ) return self.add_outline_item_destination(dest, parent) - @deprecate_bookmark(bookmark="outline_item") + @deprecation_bookmark(bookmark="outline_item") def add_outline_item_dict( self, outline_item: OutlineItemType, @@ -1368,7 +1375,7 @@ def add_outline_item_dict( return self.add_outline_item_destination(outline_item_object, parent, before) - @deprecate_bookmark(bookmark="outline_item") + @deprecation_bookmark(bookmark="outline_item") def add_bookmark_dict( self, outline_item: OutlineItemType, parent: Optional[TreeObject] = None ) -> IndirectObject: # pragma: no cover @@ -1377,10 +1384,12 @@ def add_bookmark_dict( Use :meth:`add_outline_item_dict` instead. """ - deprecate_with_replacement("add_bookmark_dict", "add_outline_item_dict") + deprecation_with_replacement( + "add_bookmark_dict", "add_outline_item_dict", "3.0.0" + ) return self.add_outline_item_dict(outline_item, parent) - @deprecate_bookmark(bookmark="outline_item") + @deprecation_bookmark(bookmark="outline_item") def addBookmarkDict( self, outline_item: OutlineItemType, parent: Optional[TreeObject] = None ) -> IndirectObject: # pragma: no cover @@ -1389,7 +1398,9 @@ def addBookmarkDict( Use :meth:`add_outline_item_dict` instead. """ - deprecate_with_replacement("addBookmarkDict", "add_outline_item_dict") + deprecation_with_replacement( + "addBookmarkDict", "add_outline_item_dict", "3.0.0" + ) return self.add_outline_item_dict(outline_item, parent) def add_outline_item( @@ -1484,7 +1495,7 @@ def add_bookmark( Use :meth:`add_outline_item` instead. """ - deprecate_with_replacement("add_bookmark", "add_outline_item") + deprecation_with_replacement("add_bookmark", "add_outline_item", "3.0.0") return self.add_outline_item( title, pagenum, @@ -1511,7 +1522,7 @@ def addBookmark( Use :meth:`add_outline_item` instead. """ - deprecate_with_replacement("addBookmark", "add_outline_item") + deprecation_with_replacement("addBookmark", "add_outline_item", "3.0.0") return self.add_outline_item( title, pagenum, @@ -1557,8 +1568,10 @@ def add_named_destination_object( new_term = "page_destination" warnings.warn( message=( - f"{old_term} is deprecated as an argument. Use {new_term} instead" - ) + f"{old_term} is deprecated as an argument and will be " + f"removed in PyPDF2 4.0.0. Use {new_term} instead" + ), + category=DeprecationWarning, ) page_destination = dest if page_destination is None: # deprecated @@ -1579,8 +1592,8 @@ def addNamedDestinationObject( Use :meth:`add_named_destination_object` instead. """ - deprecate_with_replacement( - "addNamedDestinationObject", "add_named_destination_object" + deprecation_with_replacement( + "addNamedDestinationObject", "add_named_destination_object", "3.0.0" ) return self.add_named_destination_object(dest) @@ -1599,8 +1612,10 @@ def add_named_destination( new_term = "page_number" warnings.warn( message=( - f"{old_term} is deprecated as an argument. Use {new_term} instead" - ) + f"{old_term} is deprecated as an argument and will be " + f"removed in PyPDF2 4.0.0. Use {new_term} instead" + ), + category=DeprecationWarning, ) page_number = pagenum if page_number is None: @@ -1631,7 +1646,9 @@ def addNamedDestination( Use :meth:`add_named_destination` instead. """ - deprecate_with_replacement("addNamedDestination", "add_named_destination") + deprecation_with_replacement( + "addNamedDestination", "add_named_destination", "3.0.0" + ) return self.add_named_destination(title, pagenum) def remove_links(self) -> None: @@ -1649,7 +1666,7 @@ def removeLinks(self) -> None: # pragma: no cover Use :meth:`remove_links` instead. """ - deprecate_with_replacement("removeLinks", "remove_links") + deprecation_with_replacement("removeLinks", "remove_links", "3.0.0") return self.remove_links() def remove_images(self, ignore_byte_string_object: bool = False) -> None: @@ -1737,7 +1754,7 @@ def removeImages( Use :meth:`remove_images` instead. """ - deprecate_with_replacement("removeImages", "remove_images") + deprecation_with_replacement("removeImages", "remove_images", "3.0.0") return self.remove_images(ignoreByteStringObject) def remove_text(self, ignore_byte_string_object: bool = False) -> None: @@ -1792,7 +1809,7 @@ def removeText( Use :meth:`remove_text` instead. """ - deprecate_with_replacement("removeText", "remove_text") + deprecation_with_replacement("removeText", "remove_text", "3.0.0") return self.remove_text(ignoreByteStringObject) def add_uri( @@ -1818,7 +1835,9 @@ def add_uri( """ if pagenum is not None: warnings.warn( - "The 'pagenum' argument of add_uri is deprecated. Use 'page_number' instead." + "The 'pagenum' argument of add_uri is deprecated and will be " + "removed in PyPDF2 4.0.0. Use 'page_number' instead.", + category=DeprecationWarning, ) page_number = pagenum page_link = self.get_object(self._pages)[PA.KIDS][page_number] # type: ignore @@ -1880,7 +1899,7 @@ def addURI( Use :meth:`add_uri` instead. """ - deprecate_with_replacement("addURI", "add_uri") + deprecation_with_replacement("addURI", "add_uri", "3.0.0") return self.add_uri(pagenum, uri, rect, border) def add_link( @@ -1892,7 +1911,7 @@ def add_link( fit: FitType = "/Fit", *args: ZoomArgType, ) -> None: - deprecate_with_replacement( + deprecation_with_replacement( "add_link", "add_annotation(AnnotationBuilder.link(...))" ) @@ -1955,7 +1974,7 @@ def getPageLayout(self) -> Optional[LayoutType]: # pragma: no cover Use :py:attr:`page_layout` instead. """ - deprecate_with_replacement("getPageLayout", "page_layout") + deprecation_with_replacement("getPageLayout", "page_layout", "3.0.0") return self._get_page_layout() def _set_page_layout(self, layout: Union[NameObject, LayoutType]) -> None: @@ -2023,8 +2042,8 @@ def setPageLayout(self, layout: LayoutType) -> None: # pragma: no cover Use :py:attr:`page_layout` instead. """ - deprecate_with_replacement( - "writer.setPageLayout(val)", "writer.page_layout = val" + deprecation_with_replacement( + "writer.setPageLayout(val)", "writer.page_layout = val", "3.0.0" ) return self._set_page_layout(layout) @@ -2064,7 +2083,7 @@ def pageLayout(self) -> Optional[LayoutType]: # pragma: no cover Use :py:attr:`page_layout` instead. """ - deprecate_with_replacement("pageLayout", "page_layout") + deprecation_with_replacement("pageLayout", "page_layout", "3.0.0") return self.page_layout @pageLayout.setter @@ -2074,7 +2093,7 @@ def pageLayout(self, layout: LayoutType) -> None: # pragma: no cover Use :py:attr:`page_layout` instead. """ - deprecate_with_replacement("pageLayout", "page_layout") + deprecation_with_replacement("pageLayout", "page_layout", "3.0.0") self.page_layout = layout _valid_modes = ( @@ -2098,7 +2117,7 @@ def getPageMode(self) -> Optional[PagemodeType]: # pragma: no cover Use :py:attr:`page_mode` instead. """ - deprecate_with_replacement("getPageMode", "page_mode") + deprecation_with_replacement("getPageMode", "page_mode", "3.0.0") return self._get_page_mode() def set_page_mode(self, mode: PagemodeType) -> None: @@ -2123,7 +2142,9 @@ def setPageMode(self, mode: PagemodeType) -> None: # pragma: no cover Use :py:attr:`page_mode` instead. """ - deprecate_with_replacement("writer.setPageMode(val)", "writer.page_mode = val") + deprecation_with_replacement( + "writer.setPageMode(val)", "writer.page_mode = val", "3.0.0" + ) self.set_page_mode(mode) @property @@ -2160,7 +2181,7 @@ def pageMode(self) -> Optional[PagemodeType]: # pragma: no cover Use :py:attr:`page_mode` instead. """ - deprecate_with_replacement("pageMode", "page_mode") + deprecation_with_replacement("pageMode", "page_mode", "3.0.0") return self.page_mode @pageMode.setter @@ -2170,7 +2191,7 @@ def pageMode(self, mode: PagemodeType) -> None: # pragma: no cover Use :py:attr:`page_mode` instead. """ - deprecate_with_replacement("pageMode", "page_mode") + deprecation_with_replacement("pageMode", "page_mode", "3.0.0") self.page_mode = mode def add_annotation(self, page_number: int, annotation: Dict[str, Any]) -> None: @@ -2306,7 +2327,7 @@ def append( None, fileobj, outline_item, pages, import_outline, excluded_fields ) - @deprecate_bookmark(bookmark="outline_item", import_bookmarks="import_outline") + @deprecation_bookmark(bookmark="outline_item", import_bookmarks="import_outline") def merge( self, position: Optional[int], @@ -2662,7 +2683,7 @@ def close(self) -> None: """To match the functions from Merger""" return - # @deprecate_bookmark(bookmark="outline_item") + # @deprecation_bookmark(bookmark="outline_item") def find_outline_item( self, outline_item: Dict[str, Any], @@ -2693,7 +2714,7 @@ def find_outline_item( else: return None - @deprecate_bookmark(bookmark="outline_item") + @deprecation_bookmark(bookmark="outline_item") def find_bookmark( self, outline_item: Dict[str, Any], @@ -2797,5 +2818,5 @@ def _create_outline_item( class PdfFileWriter(PdfWriter): # pragma: no cover def __init__(self, *args: Any, **kwargs: Any) -> None: - deprecate_with_replacement("PdfFileWriter", "PdfWriter") + deprecation_with_replacement("PdfFileWriter", "PdfWriter", "3.0.0") super().__init__(*args, **kwargs) diff --git a/PyPDF2/errors.py b/PyPDF2/errors.py index d00bc7c12..a84b05691 100644 --- a/PyPDF2/errors.py +++ b/PyPDF2/errors.py @@ -5,6 +5,12 @@ """ +class DeprecationError(Exception): + """Raised when a deprecated feature is used.""" + + pass + + class DependencyError(Exception): pass diff --git a/PyPDF2/generic/_base.py b/PyPDF2/generic/_base.py index 872c529ad..00b9c17bf 100644 --- a/PyPDF2/generic/_base.py +++ b/PyPDF2/generic/_base.py @@ -37,7 +37,7 @@ from .._utils import ( StreamType, b_, - deprecate_with_replacement, + deprecation_with_replacement, hex_str, hexencode, logger_warning, @@ -119,7 +119,7 @@ def get_object(self) -> Optional["PdfObject"]: return self def getObject(self) -> Optional["PdfObject"]: # pragma: no cover - deprecate_with_replacement("getObject", "get_object") + deprecation_with_replacement("getObject", "get_object", "3.0.0") return self.get_object() def write_to_stream( @@ -153,7 +153,7 @@ def read_from_stream(stream: StreamType) -> "NullObject": def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) def __repr__(self) -> str: @@ -161,7 +161,7 @@ def __repr__(self) -> str: @staticmethod def readFromStream(stream: StreamType) -> "NullObject": # pragma: no cover - deprecate_with_replacement("readFromStream", "read_from_stream") + deprecation_with_replacement("readFromStream", "read_from_stream", "3.0.0") return NullObject.read_from_stream(stream) @@ -202,7 +202,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) @staticmethod @@ -218,7 +218,7 @@ def read_from_stream(stream: StreamType) -> "BooleanObject": @staticmethod def readFromStream(stream: StreamType) -> "BooleanObject": # pragma: no cover - deprecate_with_replacement("readFromStream", "read_from_stream") + deprecation_with_replacement("readFromStream", "read_from_stream", "3.0.0") return BooleanObject.read_from_stream(stream) @@ -284,7 +284,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) @staticmethod @@ -318,7 +318,7 @@ def read_from_stream(stream: StreamType, pdf: Any) -> "IndirectObject": # PdfRe def readFromStream( stream: StreamType, pdf: Any # PdfReader ) -> "IndirectObject": # pragma: no cover - deprecate_with_replacement("readFromStream", "read_from_stream") + deprecation_with_replacement("readFromStream", "read_from_stream", "3.0.0") return IndirectObject.read_from_stream(stream, pdf) @@ -363,7 +363,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) @@ -397,7 +397,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) @staticmethod @@ -411,7 +411,7 @@ def read_from_stream(stream: StreamType) -> Union["NumberObject", "FloatObject"] def readFromStream( stream: StreamType, ) -> Union["NumberObject", "FloatObject"]: # pragma: no cover - deprecate_with_replacement("readFromStream", "read_from_stream") + deprecation_with_replacement("readFromStream", "read_from_stream", "3.0.0") return NumberObject.read_from_stream(stream) @@ -455,7 +455,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) @@ -537,7 +537,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) @@ -569,7 +569,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) def renumber(self) -> bytes: @@ -632,7 +632,7 @@ def read_from_stream(stream: StreamType, pdf: Any) -> "NameObject": # PdfReader def readFromStream( stream: StreamType, pdf: Any # PdfReader ) -> "NameObject": # pragma: no cover - deprecate_with_replacement("readFromStream", "read_from_stream") + deprecation_with_replacement("readFromStream", "read_from_stream", "3.0.0") return NameObject.read_from_stream(stream, pdf) diff --git a/PyPDF2/generic/_data_structures.py b/PyPDF2/generic/_data_structures.py index a60133532..19f5be9fb 100644 --- a/PyPDF2/generic/_data_structures.py +++ b/PyPDF2/generic/_data_structures.py @@ -40,6 +40,7 @@ StreamType, b_, deprecate_with_replacement, + deprecation_with_replacement, hex_str, logger_warning, read_non_whitespace, @@ -121,7 +122,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) @staticmethod @@ -153,7 +154,7 @@ def read_from_stream( def readFromStream( stream: StreamType, pdf: Any # PdfReader ) -> "ArrayObject": # pragma: no cover - deprecate_with_replacement("readFromStream", "read_from_stream") + deprecation_with_replacement("readFromStream", "read_from_stream", "3.0.0") return ArrayObject.read_from_stream(stream, pdf) @@ -295,7 +296,7 @@ def getXmpMetadata( Use :meth:`xmp_metadata` instead. """ - deprecate_with_replacement("getXmpMetadata", "xmp_metadata") + deprecation_with_replacement("getXmpMetadata", "xmp_metadata", "3.0.0") return self.xmp_metadata @property @@ -305,7 +306,7 @@ def xmpMetadata(self) -> Optional[PdfObject]: # pragma: no cover Use :meth:`xmp_metadata` instead. """ - deprecate_with_replacement("xmpMetadata", "xmp_metadata") + deprecation_with_replacement("xmpMetadata", "xmp_metadata", "3.0.0") return self.xmp_metadata def write_to_stream( @@ -322,7 +323,7 @@ def write_to_stream( def writeToStream( self, stream: StreamType, encryption_key: Union[None, str, bytes] ) -> None: # pragma: no cover - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) @staticmethod @@ -465,7 +466,7 @@ def read_unsized_from_steam(stream: StreamType, pdf: Any) -> bytes: # PdfReader def readFromStream( stream: StreamType, pdf: Any # PdfReader ) -> "DictionaryObject": # pragma: no cover - deprecate_with_replacement("readFromStream", "read_from_stream") + deprecation_with_replacement("readFromStream", "read_from_stream", "3.0.0") return DictionaryObject.read_from_stream(stream, pdf) @@ -499,7 +500,7 @@ def children(self) -> Iterable[Any]: child = child_ref.get_object() def addChild(self, child: Any, pdf: Any) -> None: # pragma: no cover - deprecate_with_replacement("addChild", "add_child") + deprecation_with_replacement("addChild", "add_child", "3.0.0") self.add_child(child, pdf) def add_child(self, child: Any, pdf: PdfWriterProtocol) -> None: @@ -561,7 +562,7 @@ def inc_parent_counter( inc_parent_counter(self, child_obj.get("/Count", 1)) def removeChild(self, child: Any) -> None: # pragma: no cover - deprecate_with_replacement("removeChild", "remove_child") + deprecation_with_replacement("removeChild", "remove_child", "3.0.0") self.remove_child(child) def _remove_node_from_tree( @@ -707,12 +708,12 @@ def hash_value_data(self) -> bytes: @property def decodedSelf(self) -> Optional["DecodedStreamObject"]: # pragma: no cover - deprecate_with_replacement("decodedSelf", "decoded_self") + deprecation_with_replacement("decodedSelf", "decoded_self", "3.0.0") return self.decoded_self @decodedSelf.setter def decodedSelf(self, value: "DecodedStreamObject") -> None: # pragma: no cover - deprecate_with_replacement("decodedSelf", "decoded_self") + deprecation_with_replacement("decodedSelf", "decoded_self", "3.0.0") self.decoded_self = value @property @@ -760,7 +761,7 @@ def initialize_from_dictionary( return retval def flateEncode(self) -> "EncodedStreamObject": # pragma: no cover - deprecate_with_replacement("flateEncode", "flate_encode") + deprecation_with_replacement("flateEncode", "flate_encode", "3.0.0") return self.flate_encode() def flate_encode(self) -> "EncodedStreamObject": @@ -791,11 +792,11 @@ def set_data(self, data: Any) -> Any: self._data = data def getData(self) -> Any: # pragma: no cover - deprecate_with_replacement("getData", "get_data") + deprecation_with_replacement("getData", "get_data", "3.0.0") return self._data def setData(self, data: Any) -> None: # pragma: no cover - deprecate_with_replacement("setData", "set_data") + deprecation_with_replacement("setData", "set_data", "3.0.0") self.set_data(data) @@ -805,12 +806,12 @@ def __init__(self) -> None: @property def decodedSelf(self) -> Optional["DecodedStreamObject"]: # pragma: no cover - deprecate_with_replacement("decodedSelf", "decoded_self") + deprecation_with_replacement("decodedSelf", "decoded_self", "3.0.0") return self.decoded_self @decodedSelf.setter def decodedSelf(self, value: DecodedStreamObject) -> None: # pragma: no cover - deprecate_with_replacement("decodedSelf", "decoded_self") + deprecation_with_replacement("decodedSelf", "decoded_self", "3.0.0") self.decoded_self = value def get_data(self) -> Union[None, str, bytes]: @@ -831,14 +832,14 @@ def get_data(self) -> Union[None, str, bytes]: return decoded._data def getData(self) -> Union[None, str, bytes]: # pragma: no cover - deprecate_with_replacement("getData", "get_data") + deprecation_with_replacement("getData", "get_data", "3.0.0") return self.get_data() def set_data(self, data: Any) -> None: # pragma: no cover raise PdfReadError("Creating EncodedStreamObject is not currently supported") def setData(self, data: Any) -> None: # pragma: no cover - deprecate_with_replacement("setData", "set_data") + deprecation_with_replacement("setData", "set_data", "3.0.0") return self.set_data(data) @@ -1114,7 +1115,7 @@ def fieldType(self) -> Optional[NameObject]: # pragma: no cover Use :py:attr:`field_type` instead. """ - deprecate_with_replacement("fieldType", "field_type") + deprecation_with_replacement("fieldType", "field_type", "3.0.0") return self.field_type @property @@ -1144,7 +1145,7 @@ def altName(self) -> Optional[str]: # pragma: no cover Use :py:attr:`alternate_name` instead. """ - deprecate_with_replacement("altName", "alternate_name") + deprecation_with_replacement("altName", "alternate_name", "3.0.0") return self.alternate_name @property @@ -1163,7 +1164,7 @@ def mappingName(self) -> Optional[str]: # pragma: no cover Use :py:attr:`mapping_name` instead. """ - deprecate_with_replacement("mappingName", "mapping_name") + deprecation_with_replacement("mappingName", "mapping_name", "3.0.0") return self.mapping_name @property @@ -1194,7 +1195,7 @@ def defaultValue(self) -> Optional[Any]: # pragma: no cover Use :py:attr:`default_value` instead. """ - deprecate_with_replacement("defaultValue", "default_value") + deprecation_with_replacement("defaultValue", "default_value", "3.0.0") return self.default_value @property @@ -1213,7 +1214,7 @@ def additionalActions(self) -> Optional[DictionaryObject]: # pragma: no cover Use :py:attr:`additional_actions` instead. """ - deprecate_with_replacement("additionalActions", "additional_actions") + deprecation_with_replacement("additionalActions", "additional_actions", "3.0.0") return self.additional_actions @@ -1296,7 +1297,7 @@ def getDestArray(self) -> "ArrayObject": # pragma: no cover Use :py:attr:`dest_array` instead. """ - deprecate_with_replacement("getDestArray", "dest_array") + deprecation_with_replacement("getDestArray", "dest_array", "3.0.0") return self.dest_array def write_to_stream( diff --git a/PyPDF2/generic/_outline.py b/PyPDF2/generic/_outline.py index 0c8b17cdf..c2e72c0ab 100644 --- a/PyPDF2/generic/_outline.py +++ b/PyPDF2/generic/_outline.py @@ -1,6 +1,6 @@ from typing import Any, Union -from .._utils import StreamType, deprecate_with_replacement +from .._utils import StreamType, deprecation_with_replacement from ._base import NameObject from ._data_structures import Destination @@ -31,5 +31,5 @@ def write_to_stream( class Bookmark(OutlineItem): # pragma: no cover def __init__(self, *args: Any, **kwargs: Any) -> None: - deprecate_with_replacement("Bookmark", "OutlineItem") + deprecation_with_replacement("Bookmark", "OutlineItem", "3.0.0") super().__init__(*args, **kwargs) diff --git a/PyPDF2/generic/_rectangle.py b/PyPDF2/generic/_rectangle.py index 2cbd1e2c4..3f41bfd59 100644 --- a/PyPDF2/generic/_rectangle.py +++ b/PyPDF2/generic/_rectangle.py @@ -1,7 +1,7 @@ import decimal from typing import Any, List, Tuple, Union -from .._utils import deprecate_no_replacement, deprecate_with_replacement +from .._utils import deprecation_no_replacement, deprecation_with_replacement from ._base import FloatObject, NumberObject from ._data_structures import ArrayObject @@ -42,7 +42,7 @@ def scale(self, sx: float, sy: float) -> "RectangleObject": def ensureIsNumber( self, value: Any ) -> Union[FloatObject, NumberObject]: # pragma: no cover - deprecate_no_replacement("ensureIsNumber") + deprecation_no_replacement("ensureIsNumber", "3.0.0") return self._ensure_is_number(value) def __repr__(self) -> str: @@ -81,35 +81,35 @@ def top(self, f: float) -> None: self[3] = FloatObject(f) def getLowerLeft_x(self) -> FloatObject: # pragma: no cover - deprecate_with_replacement("getLowerLeft_x", "left") + deprecation_with_replacement("getLowerLeft_x", "left", "3.0.0") return self.left def getLowerLeft_y(self) -> FloatObject: # pragma: no cover - deprecate_with_replacement("getLowerLeft_y", "bottom") + deprecation_with_replacement("getLowerLeft_y", "bottom", "3.0.0") return self.bottom def getUpperRight_x(self) -> FloatObject: # pragma: no cover - deprecate_with_replacement("getUpperRight_x", "right") + deprecation_with_replacement("getUpperRight_x", "right", "3.0.0") return self.right def getUpperRight_y(self) -> FloatObject: # pragma: no cover - deprecate_with_replacement("getUpperRight_y", "top") + deprecation_with_replacement("getUpperRight_y", "top", "3.0.0") return self.top def getUpperLeft_x(self) -> FloatObject: # pragma: no cover - deprecate_with_replacement("getUpperLeft_x", "left") + deprecation_with_replacement("getUpperLeft_x", "left", "3.0.0") return self.left def getUpperLeft_y(self) -> FloatObject: # pragma: no cover - deprecate_with_replacement("getUpperLeft_y", "top") + deprecation_with_replacement("getUpperLeft_y", "top", "3.0.0") return self.top def getLowerRight_x(self) -> FloatObject: # pragma: no cover - deprecate_with_replacement("getLowerRight_x", "right") + deprecation_with_replacement("getLowerRight_x", "right", "3.0.0") return self.right def getLowerRight_y(self) -> FloatObject: # pragma: no cover - deprecate_with_replacement("getLowerRight_y", "bottom") + deprecation_with_replacement("getLowerRight_y", "bottom", "3.0.0") return self.bottom @property @@ -163,41 +163,41 @@ def upper_right(self, value: List[Any]) -> None: def getLowerLeft( self, ) -> Tuple[decimal.Decimal, decimal.Decimal]: # pragma: no cover - deprecate_with_replacement("getLowerLeft", "lower_left") + deprecation_with_replacement("getLowerLeft", "lower_left", "3.0.0") return self.lower_left def getLowerRight( self, ) -> Tuple[decimal.Decimal, decimal.Decimal]: # pragma: no cover - deprecate_with_replacement("getLowerRight", "lower_right") + deprecation_with_replacement("getLowerRight", "lower_right", "3.0.0") return self.lower_right def getUpperLeft( self, ) -> Tuple[decimal.Decimal, decimal.Decimal]: # pragma: no cover - deprecate_with_replacement("getUpperLeft", "upper_left") + deprecation_with_replacement("getUpperLeft", "upper_left", "3.0.0") return self.upper_left def getUpperRight( self, ) -> Tuple[decimal.Decimal, decimal.Decimal]: # pragma: no cover - deprecate_with_replacement("getUpperRight", "upper_right") + deprecation_with_replacement("getUpperRight", "upper_right", "3.0.0") return self.upper_right def setLowerLeft(self, value: Tuple[float, float]) -> None: # pragma: no cover - deprecate_with_replacement("setLowerLeft", "lower_left") + deprecation_with_replacement("setLowerLeft", "lower_left", "3.0.0") self.lower_left = value # type: ignore def setLowerRight(self, value: Tuple[float, float]) -> None: # pragma: no cover - deprecate_with_replacement("setLowerRight", "lower_right") + deprecation_with_replacement("setLowerRight", "lower_right", "3.0.0") self[2], self[1] = (self._ensure_is_number(x) for x in value) def setUpperLeft(self, value: Tuple[float, float]) -> None: # pragma: no cover - deprecate_with_replacement("setUpperLeft", "upper_left") + deprecation_with_replacement("setUpperLeft", "upper_left", "3.0.0") self[0], self[3] = (self._ensure_is_number(x) for x in value) def setUpperRight(self, value: Tuple[float, float]) -> None: # pragma: no cover - deprecate_with_replacement("setUpperRight", "upper_right") + deprecation_with_replacement("setUpperRight", "upper_right", "3.0.0") self[2], self[3] = (self._ensure_is_number(x) for x in value) @property @@ -205,7 +205,7 @@ def width(self) -> decimal.Decimal: return self.right - self.left def getWidth(self) -> decimal.Decimal: # pragma: no cover - deprecate_with_replacement("getWidth", "width") + deprecation_with_replacement("getWidth", "width", "3.0.0") return self.width @property @@ -213,53 +213,53 @@ def height(self) -> decimal.Decimal: return self.top - self.bottom def getHeight(self) -> decimal.Decimal: # pragma: no cover - deprecate_with_replacement("getHeight", "height") + deprecation_with_replacement("getHeight", "height", "3.0.0") return self.height @property def lowerLeft(self) -> Tuple[decimal.Decimal, decimal.Decimal]: # pragma: no cover - deprecate_with_replacement("lowerLeft", "lower_left") + deprecation_with_replacement("lowerLeft", "lower_left", "3.0.0") return self.lower_left @lowerLeft.setter def lowerLeft( self, value: Tuple[decimal.Decimal, decimal.Decimal] ) -> None: # pragma: no cover - deprecate_with_replacement("lowerLeft", "lower_left") + deprecation_with_replacement("lowerLeft", "lower_left", "3.0.0") self.lower_left = value @property def lowerRight(self) -> Tuple[decimal.Decimal, decimal.Decimal]: # pragma: no cover - deprecate_with_replacement("lowerRight", "lower_right") + deprecation_with_replacement("lowerRight", "lower_right", "3.0.0") return self.lower_right @lowerRight.setter def lowerRight( self, value: Tuple[decimal.Decimal, decimal.Decimal] ) -> None: # pragma: no cover - deprecate_with_replacement("lowerRight", "lower_right") + deprecation_with_replacement("lowerRight", "lower_right", "3.0.0") self.lower_right = value @property def upperLeft(self) -> Tuple[decimal.Decimal, decimal.Decimal]: # pragma: no cover - deprecate_with_replacement("upperLeft", "upper_left") + deprecation_with_replacement("upperLeft", "upper_left", "3.0.0") return self.upper_left @upperLeft.setter def upperLeft( self, value: Tuple[decimal.Decimal, decimal.Decimal] ) -> None: # pragma: no cover - deprecate_with_replacement("upperLeft", "upper_left") + deprecation_with_replacement("upperLeft", "upper_left", "3.0.0") self.upper_left = value @property def upperRight(self) -> Tuple[decimal.Decimal, decimal.Decimal]: # pragma: no cover - deprecate_with_replacement("upperRight", "upper_right") + deprecation_with_replacement("upperRight", "upper_right", "3.0.0") return self.upper_right @upperRight.setter def upperRight( self, value: Tuple[decimal.Decimal, decimal.Decimal] ) -> None: # pragma: no cover - deprecate_with_replacement("upperRight", "upper_right") + deprecation_with_replacement("upperRight", "upper_right", "3.0.0") self.upper_right = value diff --git a/PyPDF2/types.py b/PyPDF2/types.py index 9683c1edd..92cba6fe9 100644 --- a/PyPDF2/types.py +++ b/PyPDF2/types.py @@ -20,8 +20,6 @@ BorderArrayType: TypeAlias = List[Union[NameObject, NumberObject, ArrayObject]] OutlineItemType: TypeAlias = Union[OutlineItem, Destination] -# BookmarkTypes is deprecated. Use OutlineItemType instead -BookmarkTypes: TypeAlias = OutlineItemType # Remove with PyPDF2==3.0.0 FitType: TypeAlias = Literal[ "/Fit", "/XYZ", "/FitH", "/FitV", "/FitR", "/FitB", "/FitBH", "/FitBV" ] @@ -29,13 +27,11 @@ ZoomArgType: TypeAlias = Union[NumberObject, NullObject, float] ZoomArgsType: TypeAlias = List[ZoomArgType] -# Recursive types are not yet supported by mypy: -# OutlinesType = List[Union[Destination, "OutlinesType"]] +# Recursive types like the following are not yet supported by mypy: +# OutlineType = List[Union[Destination, "OutlineType"]] # See https://github.com/python/mypy/issues/731 # Hence use this for the moment: OutlineType = List[Union[Destination, List[Union[Destination, List[Destination]]]]] -# OutlinesType is deprecated. Use OutlineType instead -OutlinesType: TypeAlias = OutlineType # Remove with PyPDF2==3.0.0 LayoutType: TypeAlias = Literal[ "/NoLayout", diff --git a/PyPDF2/xmp.py b/PyPDF2/xmp.py index b93b797bd..de4328239 100644 --- a/PyPDF2/xmp.py +++ b/PyPDF2/xmp.py @@ -23,7 +23,11 @@ from xml.dom.minidom import parseString from xml.parsers.expat import ExpatError -from ._utils import StreamType, deprecate_with_replacement +from ._utils import ( + StreamType, + deprecate_with_replacement, + deprecation_with_replacement, +) from .errors import PdfReadError from .generic import ContentStream, PdfObject @@ -242,7 +246,7 @@ def writeToStream( Use :meth:`write_to_stream` instead. """ - deprecate_with_replacement("writeToStream", "write_to_stream") + deprecation_with_replacement("writeToStream", "write_to_stream", "3.0.0") self.write_to_stream(stream, encryption_key) def get_element(self, about_uri: str, namespace: str, name: str) -> Iterator[Any]: @@ -261,7 +265,7 @@ def getElement( Use :meth:`get_element` instead. """ - deprecate_with_replacement("getElement", "get_element") + deprecation_with_replacement("getElement", "get_element", "3.0.0") return self.get_element(aboutUri, namespace, name) def get_nodes_in_namespace(self, about_uri: str, namespace: str) -> Iterator[Any]: @@ -283,7 +287,9 @@ def getNodesInNamespace( Use :meth:`get_nodes_in_namespace` instead. """ - deprecate_with_replacement("getNodesInNamespace", "get_nodes_in_namespace") + deprecation_with_replacement( + "getNodesInNamespace", "get_nodes_in_namespace", "3.0.0" + ) return self.get_nodes_in_namespace(aboutUri, namespace) def _get_text(self, element: XmlElement) -> str: @@ -450,12 +456,12 @@ def xmp_metadataDate(self, value: datetime.datetime) -> None: # pragma: no cove @property def xmp_creatorTool(self) -> str: # pragma: no cover - deprecate_with_replacement("xmp_creatorTool", "xmp_creator_tool") + deprecation_with_replacement("xmp_creatorTool", "xmp_creator_tool", "3.0.0") 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") + deprecation_with_replacement("xmp_creatorTool", "xmp_creator_tool", "3.0.0") self.xmp_creator_tool = value xmpmm_document_id = property(_getter_single(XMPMM_NAMESPACE, "DocumentID")) @@ -465,12 +471,12 @@ def xmp_creatorTool(self, value: str) -> None: # pragma: no cover @property def xmpmm_documentId(self) -> str: # pragma: no cover - deprecate_with_replacement("xmpmm_documentId", "xmpmm_document_id") + deprecation_with_replacement("xmpmm_documentId", "xmpmm_document_id", "3.0.0") 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") + deprecation_with_replacement("xmpmm_documentId", "xmpmm_document_id", "3.0.0") self.xmpmm_document_id = value xmpmm_instance_id = property(_getter_single(XMPMM_NAMESPACE, "InstanceID")) @@ -481,12 +487,12 @@ def xmpmm_documentId(self, value: str) -> None: # pragma: no cover @property def xmpmm_instanceId(self) -> str: # pragma: no cover - deprecate_with_replacement("xmpmm_instanceId", "xmpmm_instance_id") + deprecation_with_replacement("xmpmm_instanceId", "xmpmm_instance_id", "3.0.0") return cast(str, 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") + deprecation_with_replacement("xmpmm_instanceId", "xmpmm_instance_id", "3.0.0") self.xmpmm_instance_id = value @property diff --git a/docs/conf.py b/docs/conf.py index 41e5fba22..43a8394e1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,7 +27,7 @@ # -- General configuration --------------------------------------------------- - +myst_all_links_external = True # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. diff --git a/docs/dev/deprecations.md b/docs/dev/deprecations.md index f439429f3..89f778e44 100644 --- a/docs/dev/deprecations.md +++ b/docs/dev/deprecations.md @@ -29,14 +29,14 @@ we do it: and when it will happen. The docs let users know about the deprecation and when it will happen and the new function. The CHANGELOG informs about it. -2. `(x+1).0.0`: Remove / change the code in the breaking way, - but keep/add DeprecationWarnings messages. +2. `(x+1).0.0`: Remove / change the code in the breaking way by replacing + DeprecationWarnings by DeprecationErrors. We do this to help people who didn't look at the warnings before. The CHANGELOG informs about it. -3. `(x+2).0.0`: The DeprecationWarnings are removed. +3. `(x+2).0.0`: The DeprecationErrors are removed. -This means the users have 3 warnings in the CHANGELOG, a PendingDeprecationWarning -until the next major release and a DeprecationWarning until the major release +This means the users have 3 warnings in the CHANGELOG, a DeprecationWarning +until the next major release and a DeprecationError until the major release after that. Please note that adding warnings can be a breaking change for some users; most diff --git a/tests/test_generic.py b/tests/test_generic.py index cffacc964..b02692d97 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -967,7 +967,10 @@ def test_cloning(caplog): obj3 = obj2.indirect_reference.clone(writer) assert len(writer._objects) == n + 1 assert obj2.indirect_reference == obj3.indirect_reference - assert obj2.indirect_reference == obj2._reference_clone(obj2, writer).indirect_reference + assert ( + obj2.indirect_reference + == obj2._reference_clone(obj2, writer).indirect_reference + ) assert len(writer._objects) == n + 1 assert obj2.indirect_reference == obj3.indirect_reference diff --git a/tests/test_merger.py b/tests/test_merger.py index f33c29d7e..f5d078900 100644 --- a/tests/test_merger.py +++ b/tests/test_merger.py @@ -7,6 +7,7 @@ import PyPDF2 from PyPDF2 import PdfMerger, PdfReader, PdfWriter +from PyPDF2.errors import DeprecationError from PyPDF2.generic import Destination, Fit from . import get_pdf_from_url @@ -664,44 +665,38 @@ def test_iss1145_with_writer(): merger.close() -def test_deprecate_bookmark_decorator_warning(): +def test_deprecation_bookmark_decorator_deprecationexcp(): reader = PdfReader(RESOURCE_ROOT / "outlines-with-invalid-destinations.pdf") merger = PdfMerger() - with pytest.warns( - UserWarning, + with pytest.raises( + DeprecationError, match="import_bookmarks is deprecated as an argument. Use import_outline instead", ): merger.merge(0, reader, import_bookmarks=True) -def test_deprecate_bookmark_decorator_warning_with_writer(): +def test_deprecation_bookmark_decorator_deprecationexcp_with_writer(): reader = PdfReader(RESOURCE_ROOT / "outlines-with-invalid-destinations.pdf") merger = PdfWriter() - with pytest.warns( - UserWarning, + with pytest.raises( + DeprecationError, match="import_bookmarks is deprecated as an argument. Use import_outline instead", ): merger.merge(0, reader, import_bookmarks=True) -@pytest.mark.filterwarnings("ignore::UserWarning") -def test_deprecate_bookmark_decorator_output(): +def test_deprecation_bookmark_decorator_output(): reader = PdfReader(RESOURCE_ROOT / "outlines-with-invalid-destinations.pdf") merger = PdfMerger() - merger.merge(0, reader, import_bookmarks=True) - first_oi_title = 'Valid Destination: Action /GoTo Named Destination "section.1"' - assert merger.outline[0].title == first_oi_title + with pytest.raises(DeprecationError): + merger.merge(0, reader, import_bookmarks=True) -@pytest.mark.filterwarnings("ignore::UserWarning") -def test_deprecate_bookmark_decorator_output_with_writer(): +def test_deprecation_bookmark_decorator_output_with_writer(): reader = PdfReader(RESOURCE_ROOT / "outlines-with-invalid-destinations.pdf") merger = PdfWriter() - merger.merge(0, reader, import_bookmarks=True) - first_oi_title = 'Valid Destination: Action /GoTo Named Destination "section.1"' - # TODO? : add outline property ??? - # assert merger.outline[0].title == first_oi_title - assert merger.find_outline_item(first_oi_title) == [0] + with pytest.raises(DeprecationError): + merger.merge(0, reader, import_bookmarks=True) @pytest.mark.external diff --git a/tests/test_page.py b/tests/test_page.py index 2c2ea3a9f..ee4af14a0 100644 --- a/tests/test_page.py +++ b/tests/test_page.py @@ -10,7 +10,7 @@ from PyPDF2 import PdfReader, PdfWriter, Transformation from PyPDF2._page import PageObject, set_custom_rtl from PyPDF2.constants import PageAttributes as PG -from PyPDF2.errors import PdfReadWarning +from PyPDF2.errors import DeprecationError, PdfReadWarning from PyPDF2.generic import ( ArrayObject, DictionaryObject, @@ -131,8 +131,10 @@ def test_transformation_equivalence(): # Option 2: The old way page_box2 = deepcopy(page_box) page_base2 = deepcopy(page_base) - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): page_base2.mergeTransformedPage(page_box2, op, expand=False) + page_box2.add_transformation(op) + page_base2.merge_page(page_box2) # Should be the same assert page_base1[NameObject(PG.CONTENTS)] == page_base2[NameObject(PG.CONTENTS)] @@ -165,21 +167,21 @@ def test_page_transformations(): reader = PdfReader(pdf_path) page: PageObject = reader.pages[0] - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): page.mergeRotatedPage(page, 90, expand=True) - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): page.mergeRotatedScaledPage(page, 90, 1, expand=True) - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): page.mergeRotatedScaledTranslatedPage( page, 90, scale=1, tx=1, ty=1, expand=True ) - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): page.mergeRotatedTranslatedPage(page, 90, 100, 100, expand=False) - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): page.mergeScaledPage(page, 2, expand=False) - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): page.mergeScaledTranslatedPage(page, 1, 1, 1) - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): page.mergeTranslatedPage(page, 100, 100, expand=False) page.add_transformation((1, 0, 0, 0, 0, 0)) diff --git a/tests/test_reader.py b/tests/test_reader.py index 25018ae0f..fda8f929f 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -11,6 +11,7 @@ from PyPDF2.constants import ImageAttributes as IA from PyPDF2.constants import PageAttributes as PG from PyPDF2.errors import ( + DeprecationError, EmptyFileError, FileNotDecryptedError, PdfReadError, @@ -739,11 +740,11 @@ def test_convert_to_int_error(): def test_convertToInt_deprecated(): msg = ( - "convertToInt is deprecated and will be removed in PyPDF2 3.0.0. " + "convertToInt is deprecated and was removed in PyPDF2 3.0.0. " "Use convert_to_int instead." ) - with pytest.warns( - PendingDeprecationWarning, + with pytest.raises( + DeprecationError, match=msg, ): assert convertToInt(b"\x01", 8) == 1 diff --git a/tests/test_utils.py b/tests/test_utils.py index a5f5fa186..1f67878db 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -10,7 +10,7 @@ File, _get_max_pdf_version_header, _human_readable_bytes, - deprecate_bookmark, + deprecation_bookmark, mark_location, matrix_multiply, read_block_backwards, @@ -20,7 +20,7 @@ skip_over_comment, skip_over_whitespace, ) -from PyPDF2.errors import PdfReadError, PdfStreamError +from PyPDF2.errors import DeprecationError, PdfReadError, PdfStreamError from . import get_pdf_from_url @@ -109,7 +109,7 @@ def test_b(): def test_deprecate_no_replacement(): - with pytest.warns(PendingDeprecationWarning) as warn: + with pytest.warns(DeprecationWarning) as warn: PyPDF2._utils.deprecate_no_replacement("foo") error_msg = "foo is deprecated and will be removed in PyPDF2 3.0.0." assert warn[0].message.args[0] == error_msg @@ -236,17 +236,14 @@ def test_read_block_backwards_exception(): assert exc.value.args[0] == "Could not read malformed PDF file" -def test_deprecate_bookmark(): - @deprecate_bookmark(old_param="new_param") +def test_deprecation_bookmark(): + @deprecation_bookmark(old_param="new_param") def foo(old_param=1, baz=2): return old_param * baz - with pytest.raises(TypeError) as exc: + with pytest.raises(DeprecationError) as exc: foo(old_param=12, new_param=13) - expected_msg = ( - "foo received both old_param and new_param as an argument. " - "old_param is deprecated. Use new_param instead." - ) + expected_msg = "old_param is deprecated as an argument. Use new_param instead" assert exc.value.args[0] == expected_msg diff --git a/tests/test_writer.py b/tests/test_writer.py index f179a1443..cf3a46380 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -1,14 +1,15 @@ import os +import re from io import BytesIO from pathlib import Path import pytest from PyPDF2 import PageObject, PdfMerger, PdfReader, PdfWriter -from PyPDF2.errors import PageSizeNotDefinedError +from PyPDF2.errors import DeprecationError, PageSizeNotDefinedError from PyPDF2.generic import ( - Fit, ArrayObject, + Fit, IndirectObject, NameObject, NumberObject, @@ -112,7 +113,7 @@ def writer_operate(writer): ) writer.add_blank_page() writer.add_uri(2, "https://example.com", RectangleObject([0, 0, 100, 100])) - with pytest.warns(PendingDeprecationWarning): + with pytest.raises(DeprecationError): writer.add_link(2, 1, RectangleObject([0, 0, 100, 100])) assert writer._get_page_layout() is None writer.page_layout = "broken" @@ -582,9 +583,14 @@ def test_add_link(): for page in reader.pages: writer.add_page(page) - with pytest.warns( - PendingDeprecationWarning, - match="add_link is deprecated and will be removed in PyPDF2", + with pytest.raises( + DeprecationError, + match=( + re.escape( + "add_link is deprecated and was removed in PyPDF2 3.0.0. " + "Use add_annotation(AnnotationBuilder.link(...)) instead." + ) + ), ): writer.add_link( 1, @@ -791,17 +797,17 @@ def test_add_single_annotation(): writer.write(fp) # Cleanup - os.remove(target) # remove for testing + os.remove(target) # comment out for testing -def test_deprecate_bookmark_decorator(): +def test_deprecation_bookmark_decorator(): reader = PdfReader(RESOURCE_ROOT / "outlines-with-invalid-destinations.pdf") page = reader.pages[0] outline_item = reader.outline[0] writer = PdfWriter() writer.add_page(page) - with pytest.warns( - UserWarning, + with pytest.raises( + DeprecationError, match="bookmark is deprecated as an argument. Use outline_item instead", ): writer.add_outline_item_dict(bookmark=outline_item) @@ -827,7 +833,7 @@ def test_colors_in_outline_item(): assert [str(c) for c in outline_item.color] == [str(p) for p in purple_rgb] # Cleanup - os.remove(target) # remove for testing + os.remove(target) # comment out for testing @pytest.mark.samples