Skip to content

Commit 4429066

Browse files
DEV: Use relative imports (#875)
This is important for some PyPDF2 developers development workflows. It allows them to compare changes more easily. Additionally, some imports were moved from function-level to module-level. See #865 (comment) Co-authored-by: pubpub-zz <4083478+pubpub-zz@users.noreply.github.com>
1 parent 98f72e4 commit 4429066

12 files changed

+129
-133
lines changed

PyPDF2/__init__.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
from PyPDF2._merger import PdfFileMerger
2-
from PyPDF2._reader import PdfFileReader
3-
from PyPDF2._version import __version__
4-
from PyPDF2._writer import PdfFileWriter
5-
from PyPDF2.pagerange import PageRange, parse_filename_page_ranges
6-
from PyPDF2.papersizes import PaperSize
1+
from ._merger import PdfFileMerger
2+
from ._reader import PdfFileReader
3+
from ._version import __version__
4+
from ._writer import PdfFileWriter
5+
from .pagerange import PageRange, parse_filename_page_ranges
6+
from .papersizes import PaperSize
77

88
__all__ = [
99
"__version__",

PyPDF2/_merger.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828
from io import BytesIO, FileIO, IOBase
2929
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union, cast
3030

31-
from PyPDF2._page import PageObject
32-
from PyPDF2._reader import PdfFileReader
33-
from PyPDF2._writer import PdfFileWriter
34-
from PyPDF2.constants import PagesAttributes as PA
35-
from PyPDF2.generic import (
31+
from ._page import PageObject
32+
from ._reader import PdfFileReader
33+
from ._writer import PdfFileWriter
34+
from .constants import PagesAttributes as PA
35+
from .generic import (
3636
ArrayObject,
3737
Bookmark,
3838
Destination,
@@ -46,16 +46,16 @@
4646
TreeObject,
4747
createStringObject,
4848
)
49-
from PyPDF2.pagerange import PageRange, PageRangeSpec
50-
from PyPDF2.types import (
49+
from .pagerange import PageRange, PageRangeSpec
50+
from .types import (
5151
BookmarkTypes,
5252
LayoutType,
5353
OutlinesType,
5454
PagemodeType,
5555
ZoomArgsType,
5656
ZoomArgType,
5757
)
58-
from PyPDF2.utils import StrByteType, str_
58+
from .utils import StrByteType, str_
5959

6060
ERR_CLOSED_WRITER = "close() was called and thus the writer cannot be used anymore"
6161

PyPDF2/_page.py

+12-13
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,10 @@
4242
cast,
4343
)
4444

45-
from PyPDF2 import utils
46-
from PyPDF2.constants import PageAttributes as PG
47-
from PyPDF2.constants import Ressources as RES
48-
from PyPDF2.errors import PageSizeNotDefinedError
49-
from PyPDF2.generic import (
45+
from .constants import PageAttributes as PG
46+
from .constants import Ressources as RES
47+
from .errors import PageSizeNotDefinedError
48+
from .generic import (
5049
ArrayObject,
5150
ContentStream,
5251
DictionaryObject,
@@ -58,7 +57,7 @@
5857
RectangleObject,
5958
TextStringObject,
6059
)
61-
from PyPDF2.utils import b_
60+
from .utils import b_, matrixMultiply
6261

6362

6463
def getRectangle(self: Any, name: str, defaults: Iterable[str]) -> RectangleObject:
@@ -115,7 +114,7 @@ def __init__(
115114
pdf: Optional[Any] = None, # PdfFileReader
116115
indirectRef: Optional[IndirectObject] = None,
117116
) -> None:
118-
from PyPDF2._reader import PdfFileReader
117+
from ._reader import PdfFileReader
119118

120119
DictionaryObject.__init__(self)
121120
self.pdf: Optional[PdfFileReader] = pdf
@@ -535,8 +534,8 @@ def mergeRotatedTranslatedPage(
535534
[0, 0, 1],
536535
]
537536
rtranslation: List[List[float]] = [[1, 0, 0], [0, 1, 0], [tx, ty, 1]]
538-
ctm = utils.matrixMultiply(translation, rotating)
539-
ctm = utils.matrixMultiply(ctm, rtranslation)
537+
ctm = matrixMultiply(translation, rotating)
538+
ctm = matrixMultiply(ctm, rtranslation)
540539

541540
return self.mergeTransformedPage(
542541
page2,
@@ -565,7 +564,7 @@ def mergeRotatedScaledPage(
565564
[0, 0, 1],
566565
]
567566
scaling: List[List[float]] = [[scale, 0, 0], [0, scale, 0], [0, 0, 1]]
568-
ctm = utils.matrixMultiply(rotating, scaling)
567+
ctm = matrixMultiply(rotating, scaling)
569568

570569
self.mergeTransformedPage(
571570
page2,
@@ -596,7 +595,7 @@ def mergeScaledTranslatedPage(
596595

597596
translation: List[List[float]] = [[1, 0, 0], [0, 1, 0], [tx, ty, 1]]
598597
scaling: List[List[float]] = [[scale, 0, 0], [0, scale, 0], [0, 0, 1]]
599-
ctm = utils.matrixMultiply(scaling, translation)
598+
ctm = matrixMultiply(scaling, translation)
600599

601600
return self.mergeTransformedPage(
602601
page2,
@@ -635,8 +634,8 @@ def mergeRotatedScaledTranslatedPage(
635634
[0, 0, 1],
636635
]
637636
scaling: List[List[float]] = [[scale, 0, 0], [0, scale, 0], [0, 0, 1]]
638-
ctm = utils.matrixMultiply(rotating, scaling)
639-
ctm = utils.matrixMultiply(ctm, translation)
637+
ctm = matrixMultiply(rotating, scaling)
638+
ctm = matrixMultiply(ctm, translation)
640639

641640
self.mergeTransformedPage(
642641
page2,

PyPDF2/_reader.py

+30-27
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
# POSSIBILITY OF SUCH DAMAGE.
2929

3030
import struct
31+
import re
3132
import warnings
3233
from hashlib import md5
3334
from io import BytesIO
@@ -44,20 +45,19 @@
4445
cast,
4546
)
4647

47-
from PyPDF2 import utils
48-
from PyPDF2._page import PageObject
49-
from PyPDF2._security import _alg33_1, _alg34, _alg35
50-
from PyPDF2.constants import CatalogAttributes as CA
51-
from PyPDF2.constants import CatalogDictionary as CD
52-
from PyPDF2.constants import Core as CO
53-
from PyPDF2.constants import DocumentInformationAttributes as DI
54-
from PyPDF2.constants import EncryptionDictAttributes as ED
55-
from PyPDF2.constants import PageAttributes as PG
56-
from PyPDF2.constants import PagesAttributes as PA
57-
from PyPDF2.constants import StreamAttributes as SA
58-
from PyPDF2.constants import TrailerKeys as TK
59-
from PyPDF2.errors import PdfReadError, PdfReadWarning, PdfStreamError
60-
from PyPDF2.generic import (
48+
from ._page import PageObject
49+
from ._security import _alg33_1, _alg34, _alg35
50+
from .constants import CatalogAttributes as CA
51+
from .constants import CatalogDictionary as CD
52+
from .constants import Core as CO
53+
from .constants import DocumentInformationAttributes as DI
54+
from .constants import EncryptionDictAttributes as ED
55+
from .constants import PageAttributes as PG
56+
from .constants import PagesAttributes as PA
57+
from .constants import StreamAttributes as SA
58+
from .constants import TrailerKeys as TK
59+
from .errors import PdfReadError, PdfReadWarning, PdfStreamError
60+
from .generic import (
6161
ArrayObject,
6262
BooleanObject,
6363
ByteStringObject,
@@ -79,15 +79,19 @@
7979
createStringObject,
8080
readObject,
8181
)
82-
from PyPDF2.types import OutlinesType
83-
from PyPDF2.utils import (
82+
from .types import OutlinesType
83+
from .utils import (
84+
RC4_encrypt,
8485
StrByteType,
8586
StreamType,
8687
b_,
88+
ord_,
8789
readNonWhitespace,
8890
readUntilWhitespace,
91+
skipOverComment,
92+
skipOverWhitespace,
8993
)
90-
from PyPDF2.xmp import XmpInformation
94+
from .xmp import XmpInformation
9195

9296

9397
def convertToInt(d: bytes, size: int) -> Union[int, Tuple[Any, ...]]:
@@ -923,9 +927,9 @@ def _decryptObject(
923927
key: Union[str, bytes],
924928
) -> PdfObject:
925929
if isinstance(obj, (ByteStringObject, TextStringObject)):
926-
obj = createStringObject(utils.RC4_encrypt(key, obj.original_bytes))
930+
obj = createStringObject(RC4_encrypt(key, obj.original_bytes))
927931
elif isinstance(obj, StreamObject):
928-
obj._data = utils.RC4_encrypt(key, obj._data)
932+
obj._data = RC4_encrypt(key, obj._data)
929933
elif isinstance(obj, DictionaryObject):
930934
for dictkey, value in list(obj.items()):
931935
obj[dictkey] = self._decryptObject(value, key)
@@ -940,14 +944,14 @@ def readObjectHeader(self, stream: StreamType) -> Tuple[int, int]:
940944
# object header. In reality... some files have stupid cross reference
941945
# tables that are off by whitespace bytes.
942946
extra = False
943-
utils.skipOverComment(stream)
944-
extra |= utils.skipOverWhitespace(stream)
947+
skipOverComment(stream)
948+
extra |= skipOverWhitespace(stream)
945949
stream.seek(-1, 1)
946950
idnum = readUntilWhitespace(stream)
947-
extra |= utils.skipOverWhitespace(stream)
951+
extra |= skipOverWhitespace(stream)
948952
stream.seek(-1, 1)
949953
generation = readUntilWhitespace(stream)
950-
extra |= utils.skipOverWhitespace(stream)
954+
extra |= skipOverWhitespace(stream)
951955
stream.seek(-1, 1)
952956

953957
# although it's not used, it might still be necessary to read
@@ -1263,7 +1267,6 @@ def _rebuild_xref_table(self, stream: StreamType) -> None:
12631267
self.xref = {}
12641268
stream.seek(0, 0)
12651269
f_ = stream.read(-1)
1266-
import re
12671270

12681271
for m in re.finditer(b_(r"[\r\n \t][ \t]*(\d+)[ \t]+(\d+)[ \t]+obj"), f_):
12691272
idnum = int(m.group(1))
@@ -1442,14 +1445,14 @@ def _decrypt(self, password: Union[str, bytes]) -> int:
14421445
key = _alg33_1(password, rev, keylen)
14431446
real_O = cast(bytes, encrypt["/O"].getObject())
14441447
if rev == 2:
1445-
userpass = utils.RC4_encrypt(key, real_O)
1448+
userpass = RC4_encrypt(key, real_O)
14461449
else:
14471450
val = real_O
14481451
for i in range(19, -1, -1):
14491452
new_key = b_("")
14501453
for l in range(len(key)):
1451-
new_key += b_(chr(utils.ord_(key[l]) ^ i))
1452-
val = utils.RC4_encrypt(new_key, val)
1454+
new_key += b_(chr(ord_(key[l]) ^ i))
1455+
val = RC4_encrypt(new_key, val)
14531456
userpass = val
14541457
owner_password, key = self._authenticateUserPassword(userpass)
14551458
if owner_password:

PyPDF2/_security.py

+7-8
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@
3333
from hashlib import md5
3434
from typing import Any, Tuple, Union
3535

36-
from PyPDF2 import utils
37-
from PyPDF2.generic import BooleanObject, ByteStringObject
38-
from PyPDF2.utils import b_, ord_, str_
36+
from .generic import BooleanObject, ByteStringObject
37+
from .utils import RC4_encrypt, b_, ord_, str_
3938

4039
# ref: pdf1.8 spec section 3.5.2 algorithm 3.2
4140
_encryption_padding = (
@@ -106,7 +105,7 @@ def _alg33(owner_pwd: str, user_pwd: str, rev: int, keylen: int) -> bytes:
106105
user_pwd_bytes = b_((user_pwd + str_(_encryption_padding))[:32])
107106
# 6. Encrypt the result of step 5, using an RC4 encryption function with
108107
# the encryption key obtained in step 4.
109-
val = utils.RC4_encrypt(key, user_pwd_bytes)
108+
val = RC4_encrypt(key, user_pwd_bytes)
110109
# 7. (Revision 3 or greater) Do the following 19 times: Take the output
111110
# from the previous invocation of the RC4 function and pass it as input to
112111
# a new invocation of the function; use an encryption key generated by
@@ -118,7 +117,7 @@ def _alg33(owner_pwd: str, user_pwd: str, rev: int, keylen: int) -> bytes:
118117
new_key = ""
119118
for l in range(len(key)):
120119
new_key += chr(ord_(key[l]) ^ i)
121-
val = utils.RC4_encrypt(new_key, val)
120+
val = RC4_encrypt(new_key, val)
122121
# 8. Store the output from the final invocation of the RC4 as the value of
123122
# the /O entry in the encryption dictionary.
124123
return val
@@ -163,7 +162,7 @@ def _alg34(
163162
# 2. Encrypt the 32-byte padding string shown in step 1 of algorithm 3.2,
164163
# using an RC4 encryption function with the encryption key from the
165164
# preceding step.
166-
U = utils.RC4_encrypt(key, _encryption_padding)
165+
U = RC4_encrypt(key, _encryption_padding)
167166
# 3. Store the result of step 2 as the value of the /U entry in the
168167
# encryption dictionary.
169168
return U, key
@@ -195,7 +194,7 @@ def _alg35(
195194
md5_hash = m.digest()
196195
# 4. Encrypt the 16-byte result of the hash, using an RC4 encryption
197196
# function with the encryption key from step 1.
198-
val = utils.RC4_encrypt(key, md5_hash)
197+
val = RC4_encrypt(key, md5_hash)
199198
# 5. Do the following 19 times: Take the output from the previous
200199
# invocation of the RC4 function and pass it as input to a new invocation
201200
# of the function; use an encryption key generated by taking each byte of
@@ -206,7 +205,7 @@ def _alg35(
206205
new_key = b_("")
207206
for k in key:
208207
new_key += b_(chr(ord_(k) ^ i))
209-
val = utils.RC4_encrypt(new_key, val)
208+
val = RC4_encrypt(new_key, val)
210209
# 6. Append 16 bytes of arbitrary padding to the output from the final
211210
# invocation of the RC4 function and store the 32-byte result as the value
212211
# of the U entry in the encryption dictionary.

PyPDF2/_writer.py

+16-16
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,23 @@
3232
import struct
3333
import uuid
3434
import warnings
35+
import random
36+
import time
37+
3538
from hashlib import md5
3639
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
3740

38-
from PyPDF2._page import PageObject
39-
from PyPDF2._reader import PdfFileReader
40-
from PyPDF2._security import _alg33, _alg34, _alg35
41-
from PyPDF2.constants import CatalogAttributes as CA
42-
from PyPDF2.constants import Core as CO
43-
from PyPDF2.constants import EncryptionDictAttributes as ED
44-
from PyPDF2.constants import PageAttributes as PG
45-
from PyPDF2.constants import PagesAttributes as PA
46-
from PyPDF2.constants import StreamAttributes as SA
47-
from PyPDF2.constants import TrailerKeys as TK
48-
from PyPDF2.generic import (
41+
from ._page import PageObject
42+
from ._reader import PdfFileReader
43+
from ._security import _alg33, _alg34, _alg35
44+
from .constants import CatalogAttributes as CA
45+
from .constants import Core as CO
46+
from .constants import EncryptionDictAttributes as ED
47+
from .constants import PageAttributes as PG
48+
from .constants import PagesAttributes as PA
49+
from .constants import StreamAttributes as SA
50+
from .constants import TrailerKeys as TK
51+
from .generic import (
4952
ArrayObject,
5053
BooleanObject,
5154
ByteStringObject,
@@ -65,7 +68,7 @@
6568
TreeObject,
6669
createStringObject,
6770
)
68-
from PyPDF2.types import (
71+
from .types import (
6972
BookmarkTypes,
7073
BorderArrayType,
7174
FitType,
@@ -74,7 +77,7 @@
7477
ZoomArgsType,
7578
ZoomArgType,
7679
)
77-
from PyPDF2.utils import StreamType, b_
80+
from .utils import StreamType, b_
7881

7982
logger = logging.getLogger(__name__)
8083

@@ -496,9 +499,6 @@ def encrypt(
496499
control annotations, 9 for form fields, 10 for extraction of
497500
text and graphics.
498501
"""
499-
import random
500-
import time
501-
502502
if owner_pwd is None:
503503
owner_pwd = user_pwd
504504
if use_128bit:

0 commit comments

Comments
 (0)