1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
[build-system]
requires = ["flit_core >=3.11,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "pypdf"
authors = [{ name = "Mathieu Fenniak", email = "biziqe@mathieu.fenniak.net" }]
maintainers = [{ name = "stefan6419846" }, { name = "Martin Thoma", email = "info@martin-thoma.de" }]
description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files"
readme = "README.md"
dynamic = ["version"]
license = "BSD-3-Clause"
license-files = ["LICENSE"]
requires-python = ">=3.9"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Operating System :: OS Independent",
"Topic :: Software Development :: Libraries :: Python Modules",
"Typing :: Typed",
]
dependencies = [
"typing_extensions >= 4.0; python_version < '3.11'",
]
[project.urls]
Changelog = "https://pypdf.readthedocs.io/en/latest/meta/CHANGELOG.html"
Documentation = "https://pypdf.readthedocs.io/en/latest/"
Source = "https://github.com/py-pdf/pypdf"
"Bug Reports" = "https://github.com/py-pdf/pypdf/issues"
[project.optional-dependencies]
crypto = ["cryptography"]
cryptodome = ["PyCryptodome"]
image = ["Pillow>=8.0.0"]
full = [
"cryptography",
"Pillow>=8.0.0"
]
dev = [
"flit",
"pip-tools",
"pre-commit",
"pytest-cov",
"pytest-socket",
"pytest-timeout",
"pytest-xdist",
"wheel"
]
docs = [
"myst_parser",
"sphinx",
"sphinx_rtd_theme"
]
[tool.check-wheel-contents]
package = "./pypdf"
[tool.flit.sdist]
exclude = [
".gitblame-ignore-revs",
".github/*",
".gitignore",
".gitmodules",
".pre-commit-config.yaml",
"docs/*",
"make_release.py",
"Makefile",
"requirements/*",
"sample-files/.github/*",
"sample-files/.gitignore",
"sample-files/.pre-commit-config.yaml",
"tests/pdf_cache/*",
]
include = ["resources/", "tests/", "CHANGELOG.md"]
[tool.pytest.ini_options]
#addopts = "--disable-socket"
filterwarnings = ["error"]
markers = [
"slow: Test which require more than a second",
"samples: Tests which use files from https://github.com/py-pdf/sample-files",
"enable_socket: Tests which need to download files"
]
testpaths = ["tests"]
norecursedirs = ["tests/pdf_cache"]
[tool.isort]
line_length = 79
indent = ' '
multi_line_output = 3
include_trailing_comma = true
known_third_party = ["pytest"]
[tool.coverage.run]
source = ["pypdf"]
branch = true
parallel = true
[tool.coverage.report]
# Regexes for lines to exclude from consideration
exclude_lines = [
# Have to re-enable the standard pragma
"pragma: no cover",
"@overload",
"deprecated",
# Don't complain about type-checking code not being hit by unit tests
"if TYPE_CHECKING",
# Don't complain about missing debug-only code:
"def __repr__",
"def __str__",
"if self\\.debug",
# Don't complain if tests don't hit defensive assertion code:
"raise AssertionError",
"raise NotImplementedError",
# Don't complain if non-runnable code isn't run:
"if __name__ == .__main__.:",
]
[tool.ruff]
line-length = 120
exclude = [
"sample-files/",
]
[tool.ruff.lint]
select = ["ALL"]
ignore = [
"A001", # Variable is shadowing a Python builtin
"A002", # Function argument is shadowing a Python builtin
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
"ARG001", # Unused function argument
"ARG002", # Unused method argument
"ARG004", # Unused static method argument
"B904", # Within an `except` clause, raise exceptions with
"B905", # `zip()` without an explicit `strict=` parameter
"BLE001", # Do not catch blind exception: `Exception`
"COM812", # Yes, they make the diff smaller
"D101", # Missing docstring in public class
"D102", # Missing docstring in public method
"D105", # Missing docstring in magic method
"D106", # Missing docstring in public nested class
"D107", # Missing docstring in `__init__`
"D205", # One blank line required between summary line and description
"D212", # I want multiline-docstrings to start at the second line
"D401", # First line of docstring should be in imperative mood - false positives
"D415", # First line should end with a period
"D417", # Missing argument descriptions in the docstring
"DTZ001", # The use of `datetime.datetime()` without `tzinfo` is necessary
"EM101", # Exception must not use a string literal, assign to variable first
"EM102", # Exception must not use an f-string literal, assign to variable first
"ERA001", # Found commented-out code
"FA100", # Missing `from __future__ import annotations`, but uses `typing.Dict`
"FA102", # Missing `from __future__ import annotations`, but uses PEP 604 union
"FBT001", # Boolean positional arg in function definition
"FBT002", # Boolean default value in function definition
"FBT003", # Boolean positional value in function call
"FIX002", # TODOs should typically not be in the code, but sometimes are ok
"G004", # f-string in logging statement
"N806", # non-lowercase-variable-in-function
"N814", # Camelcase `PageAttributes` imported as constant `PG`
"N817", # CamelCase `PagesAttributes` imported as acronym `PA`
"PERF203", # `try`-`except` within a loop incurs performance overhead
"PGH003", # Use specific rule codes when ignoring type issues
"PLW1510", # `subprocess.run` without explicit `check` argument
"PLW2901", # `with` statement variable `img` overwritten by assignment target
"PT011", # `pytest.raises(ValueError)` is too broad, set the `match`
"PT012", # `pytest.raises()` block should contain a single simple statement
"PT014", # Ruff bug: Duplicate of test case at index 1 in `@pytest_mark.parametrize`
"PTH123", # `open()` should be replaced by `Path.open()`
"PYI042", # Type alias `mode_str_type` should be CamelCase
"RUF001", # Detect confusable Unicode-to-Unicode units. Introduces bugs
"RUF002", # Detect confusable Unicode-to-Unicode units. Introduces bugs
"S101", # Use of `assert` detected
"S110", # `try`-`except`-`pass` detected, consider logging the exception
"SIM105", # contextlib.suppress
"SIM108", # Don't enforce ternary operators
"SLF001", # Private member accessed
"TC006", # To discuss: Add quotes to type expression in `typing.cast()`
"TD002", # Authors of TODOs can be found via git
"TD003", # For the moment, fix it later: Missing issue link on the line following this TODO
"TID252", # We want relative imports
"TRY002", # Create your own exception
"TRY003", # Avoid specifying long messages outside the exception class
"TRY004", # Prefer `TypeError` exception for invalid type
"TRY201", # Use `raise` without specifying exception name
"TRY300", # Consider moving this statement to an `else` block
"TRY301", # Abstract `raise` to an inner function
"UP006", # Non-PEP 585 annotation. As long as we are not on Python 3.11+
"UP007", # Non-PEP 604 annotation. As long as we are not on Python 3.11+
]
[tool.ruff.lint.mccabe]
max-complexity = 30 # Recommended: 10
[tool.ruff.lint.per-file-ignores]
"_cryptography.py" = ["S304", "S305"] # Use of insecure cipher / modes, aka RC4 and AES-ECB
"_encryption.py" = ["S324"]
"_writer.py" = ["S324"]
"pypdf/_codecs/symbol.py" = ["A005"] # Module shadows a Python standard-library module
"types.py" = ["A005"] # Module shadows a Python standard-library module
"pypdf/_text_extraction/__init__.py" = ["PLW0603"] # Using the global statement to update is discouraged
"docs/conf.py" = ["INP001", "PTH100"]
"json_consistency.py" = ["T201"]
"make_release.py" = ["S603", "S607", "T201"]
"pypdf/*" = ["N802", "N803"] # We first need to deprecate old stuff
"tests/*" = ["ANN001", "ANN201", "B017", "B018", "D103", "D104", "S105", "S106"]
"tests/test_workflows.py" = ["T201"]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.ruff.lint.pylint]
allow-magic-value-types = ["bytes", "float", "int", "str"]
max-args = 12 # Recommended: 5
max-branches = 36 # Recommended: 12
max-returns = 11 # Recommended: 6
max-statements = 176 # Recommended: 50
[tool.docformatter]
pre-summary-newline = true
wrap-summaries = 0
wrap-descriptions = 0
[tool.mypy]
show_error_codes = true
ignore_missing_imports = true
check_untyped_defs = true
disallow_any_generics = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_unused_configs = true
exclude = ['venv', '.venv', 'tests', 'make_release.py']
|