# Packaging for report_generator as a repository of its own. # # The split out of the monorepo has happened: the package sits in `report_generator/` beside this # file, which is what `packages.find` below looks for. In the monorepo the same sources live at # `src/persistent_storage/report_generator/` and are built by the monorepo's own pyproject; this # one is not read there. # # The dependency pins mirror the monorepo's, so that a tool split out of it does not silently start # resolving different versions of the libraries it was tested against. [build-system] requires = ["setuptools>=77.0"] build-backend = "setuptools.build_meta" [project] name = "report-generator" version = "0.1.0" description = "Builds the PDF report of a stored scan from the artifacts it produced." readme = "README.md" requires-python = ">=3.14" # PEP 639: an SPDX expression. "Proprietary" is not one; a private licence is spelled LicenseRef-*. license = "LicenseRef-Proprietary" authors = [{ name = "CipherCell" }] dependencies = [ # The CLI, its configuration files and the properties models every command is described by. "typer>=0.24.1", "typer-config>=1.5.1", "pydantic>=2.13.4", "python-dotenv>=1.2.2", "rich>=15.0.0", "pyyaml>=6.0.3", # The store: scan and artifact rows out of Postgres, artifact files out of the bucket. "SQLAlchemy>=2.0.49", "psycopg2-binary>=2.9.9", "boto3>=1.43.0", # The report: the template, and the engine that turns it into a PDF. WeasyPrint additionally # needs the native Pango and cairo libraries, which pip does not install -- see the README. "jinja2>=3.1.6", "weasyprint>=69.0", ] [project.optional-dependencies] dev = [ "pytest>=9.0.0", "mypy>=1.19.0", "ruff>=0.15.16", "mypy-boto3-s3>=1.43.31", # Reads the rendered PDF back, so the tests can check what actually came out. "pymupdf>=1.24.0", ] [project.scripts] report_generator = "report_generator.__main__:run" [tool.setuptools.packages.find] # `vendor` is deliberately included: outside the monorepo it is what supplies cc_common, # persistent_storage and the two summarisers, and `vendor/__init__.py` puts it on the path. include = ["report_generator*"] [tool.setuptools.package-data] # Loaded at runtime by __file__, so it has to be installed beside the module: the Jinja template, # the print stylesheet, the mark, and the font files the stylesheet references by relative URL. "report_generator" = ["template/**/*"] # The copies are data as far as packaging is concerned -- they are put on the path, not imported # as submodules of this package. "report_generator.vendor" = ["**/*.py", "**/py.typed"] [tool.ruff] line-length = 120 target-version = "py314" # The copies are checked where they are written, not where they are copied to. Left in, every class # they define is read twice under two import paths. exclude = ["report_generator/vendor"] [tool.ruff.lint] select = ["E", "W", "F", "I", "N", "D", "ANN", "B", "C4", "SIM", "RUF"] # RUF100: the sources carry `# noqa` for rules the monorepo's own ruff config does not select # either -- they are stale there too, just invisible, because the monorepo does not select RUF. # Flagging them here would mean editing the copies, and the copies have to stay copies. ignore = ["D203", "D213", "RUF100"] [tool.ruff.lint.pydocstyle] convention = "google" [tool.ruff.lint.isort] # What the monorepo sorts these as: it lints from a root where all three live under `src/`, which # ruff's default `src = [".", "src"]` makes first-party. Here they arrive through `vendor/` and # would be sorted as third-party instead. Declared so that this repository reports the same import # findings the monorepo does -- no more and no fewer -- and the copies can stay copies. known-first-party = ["cc_common", "persistent_storage", "cipherverifier"] [tool.mypy] strict = true python_version = "3.14" # The copies are on the path at runtime only because `vendor/__init__.py` puts them there, which # mypy does not execute. Named here so the borrowed modules resolve while still being excluded # from being checked themselves. mypy_path = ["report_generator/vendor"] exclude = ["(^|/)report_generator/vendor/"] [[tool.mypy.overrides]] module = ["weasyprint.*", "pymupdf.*"] ignore_missing_imports = true # `exclude` keeps mypy from crawling into the copies; it does not stop it following an import into # them. They are checked where they are written, so their own errors are not this repository's to # report -- their types still are, which is why they are followed at all rather than ignored. [[tool.mypy.overrides]] module = ["cc_common.*", "persistent_storage.*", "cipherverifier.*"] follow_imports = "silent" [tool.pytest.ini_options] testpaths = ["tests"]