[build-system]
requires = ["setuptools>=75.3.0", "wheel", "setuptools_scm[toml]>=8.0"]
build-backend = "setuptools.build_meta"

[project]
name = "pdftl"
dynamic = ["version"]
authors = [{ name="The pdftl developers", email="ether-jet-emerald@duck.com" }]
description = "A capable CLI tool for PDF manipulation inspired by pdftk."
readme = "README.md"
requires-python = ">=3.10"
license = "MPL-2.0"
keywords = ["pdf", "pdftk", "pdftl", "cli", "manipulation", "automation"]
classifiers = [
    "Development Status :: 3 - Alpha",
    "Environment :: Console",
    "Programming Language :: Python :: 3 :: Only",
    "Programming Language :: Python :: 3",
    "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 :: Utilities",
    "Topic :: Text Processing",
]
dependencies = [
    "pikepdf>=10.3.0",
    "rich", "defusedxml"
]

[project.urls]
Homepage = "https://github.com/pdftl/pdftl"
Issues = "https://github.com/pdftl/pdftl/issues"
Repository = "https://github.com/pdftl/pdftl"
Documentation = "https://pdftl.readthedocs.io"
Changelog = "https://github.com/pdftl/pdftl/blob/main/CHANGELOG.md"

[project.scripts]
pdftl = "pdftl.cli.main:main"

[project.optional-dependencies]
# Feature-specific dependencies
add-text = ["reportlab"]
barcode = ["pypdfium2", "zxing-cpp>=3.0,<4.0"]
crop-visible = ["pypdfium2"]
delete-blank = ["numpy"]
diff-text = ["diff-match-patch", "pypdfium2"]
dump-tables = ["tablers"]
dump-text = ["pypdfium2"]
export-fonts = ["fonttools>=4.0,<5.0"]
flatten = ["pypdfium2"]
highlight = ["pypdfium2"]
import-fonts = ["fonttools>=4.0,<5.0"]
modify-images = ["numpy"]
optimize-images = ["ocrmypdf"]
replacement-font = ["fonttools>=4.0,<5.0"]
shell-completion = ["lark", "cloudpickle"]
signing = ["pyhanko"]
simplify-vectors = ["numpy", "numba"]
subset-fonts = ["fonttools>=4.0,<5.0"]
tag = ["opendataloader_pdf"]
yaml-bookmarks = ["pyyaml"]

# All optional CLI dependencies
extras = [
    "pdftl[add-text]",
    "pdftl[barcode]",
    "pdftl[crop-visible]",
    "pdftl[delete-blank]",
    "pdftl[diff-text]",
    "pdftl[dump-tables]",
    "pdftl[dump-text]",
    "pdftl[export-fonts]",
    "pdftl[flatten]",
    "pdftl[highlight]",
    "pdftl[import-fonts]",
    "pdftl[modify-images]",
    "pdftl[optimize-images]",
    "pdftl[replacement-font]",
    "pdftl[shell-completion]",
    "pdftl[signing]",
    "pdftl[simplify-vectors]",
    "pdftl[subset-fonts]",
    "pdftl[tag]",
    "pdftl[yaml-bookmarks]",
]

# User-facing "Batteries Included" install
# Usage: pip install pdftl[full]
full = [
    "pdftl[extras]",
]

# Documentation dependencies
docs = [
    "sphinx>=7.0",
    "sphinx-rtd-theme",
    "myst-parser",
]

# Development dependencies
dev = [
    "pytest",
    "pytest-xdist",
    "pytest-mock",
    "pytest-timeout",
    "pytest-cov",
    "pytest-randomly",   # randomise test order to catch ordering-sensitive bugs
    "pytest-repeat",     # run tests N times via --count
    "pytest-bisect-tests",  # bisect flaky failures
    "filelock",          # used by conftest.py to synchronise xdist workers
    "black",
    "isort",
    "ruff",
    "toml; python_version < '3.11'",
    "hypothesis",
    "PyMuPDF", # for testing only
    "reportlab",
    "mypy",
    "cryptography", # for testing only
    "types-setuptools",
    # Include full feature set so tests run against all capabilities
    "pdftl[full]",
]

# Complete installation for maintainers/CI
# Usage: pip install pdftl[dev-all]
dev-all = [
    "pdftl[dev]",
    "pdftl[docs]",
]

[tool.setuptools_scm]
version_scheme = "post-release"
local_scheme = "dirty-tag"
version_file = "src/pdftl/_version.py"

[tool.setuptools.package-data]
"pdftl" = ["*.pyi", "py.typed"]
"pdftl.operations" = ["static/*.html"]

[tool.setuptools.packages.find]
where = ["src"]

[tool.pytest.ini_options]
pythonpath = ["src"]
minversion = "6.0"
addopts = "-s --strict-markers -rs"
testpaths = ["tests"]

filterwarnings = [
    "ignore::DeprecationWarning",
]

markers = [
    "real_encryption: mark an integration test that requires unmocked pikepdf C++ components",
    "serial: marks tests to be run serially and in isolation",
    "pdftk_compat: integration tests ported from pdftk-java",
]

# log_cli = true
# log_cli_level = "CRITICAL"
# log_cli_format = "%(message)s"

log_file = "pytest.log"
log_file_level = "DEBUG"
log_file_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_file_date_format = "%Y-%m-%d %H:%M:%S"

[tool.ruff]
line-length = 99
target-version = "py310"
extend-exclude = [
    "src/pdftl/_version.py",
    "src/pdftl/api.pyi",
    "src/pdftl/fluent.pyi",
]

[tool.ruff.lint]
# E: Error, W: Warning, F: Pyflakes, UP: Pyupgrade, BLE: Blind Except
select = ["E", "W", "F", "UP", "BLE", "W291"]
ignore = ["E203", "E402"]

[tool.ruff.lint.per-file-ignores]
"src/pdftl/cli/pipeline.py" = ["BLE001"]
"tests/**/*.py" = ["E501", "E741", "BLE001"]


[tool.isort]
profile = "black"
line_length = 99

[tool.black]
line-length = 99
target-version = ['py310']
include = '\.pyi?$'

[tool.coverage.run]
source = ["pdftl"]

[tool.coverage.report]
exclude_also = [
    # A pragma comment that excludes an entire file:
    '\A(?s:.*# pragma: exclude this file.*)\Z',
]
skip_covered = true

[[tool.mypy.overrides]]
module = "pypdfium2"
ignore_missing_imports = true  # no stubs available :-(
