[build-system] requires = ["setuptools>=68.0"] build-backend = "setuptools.build_meta" [project] name = "paperforge" dynamic = ["version"] description = "PaperForge — Obsidian + Zotero literature pipeline CLI" readme = "README.md" requires-python = ">=3.10" license = {text = "CC BY-NC-SA 4.0"} authors = [ {name = "PaperForge Contributors"} ] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering :: Information Analysis", ] dependencies = [ "requests>=2.31.0", "pymupdf>=1.23.0", "pillow>=10.0.0", "tenacity>=8.2.0", "tqdm>=4.66.0", "filelock>=3.13.0", "pyyaml>=6.0", ] [project.optional-dependencies] test = [ "pytest>=7.4.0", "pytest-snapshot>=0.9.0", "pytest-timeout>=2.2.0", "responses>=0.25.0", "pytest-mock>=3.12.0", "coverage>=7.4.0", "ruff>=0.4.0", ] vector = [ "chromadb>=0.5.0", "openai>=1.0.0", ] [project.scripts] paperforge = "paperforge.cli:main" [tool.setuptools.packages.find] where = ["."] include = ["paperforge*"] [tool.setuptools.dynamic] version = {attr = "paperforge.__version__"} [tool.setuptools.package-data] paperforge = [ "py.typed", "skills/paperforge/**", "command_files/*.md", "plugin/*.css", "plugin/*.js", "plugin/*.json", ] [tool.pytest.ini_options] addopts = "--ignore=tests/sandbox/00_TestVault/ --strict-markers" testpaths = ["tests/unit", "tests/cli", "tests/e2e", "tests/journey", "tests/chaos", "tests/audit", "tests/integration"] markers = [ "unit: Unit tests (Level 1) — fast, isolated", "cli: CLI contract tests (Level 2) — subprocess boundary", "e2e: End-to-end tests (Level 4) — temp vault", "journey: User journey tests (Level 5) — full workflows", "chaos: Destructive tests (Level 6) — abnormal scenarios", "audit: Consistency audit tests — validate L1 mocks against L4 real pipeline output", "integration: Integration tests — multi-component workflows", "slow: Tests that take >30s (skip during development)", "snapshot: Tests that use snapshot comparison", ] [tool.ruff] target-version = "py310" line-length = 120 exclude = ["paperforge/skills"] [tool.ruff.lint] select = ["E", "F", "I", "UP", "B", "SIM"] ignore = ["B904"] # raise-within-try is intentional in many worker error paths [tool.ruff.lint.per-file-ignores] # Pre-existing: undefined names in update.py (GITHUB_REPO etc. defined below function defs) "paperforge/worker/update.py" = ["F821"] # Pre-existing: undefined names in sync.py (run_search_sources, run_ingest_candidates) "paperforge/worker/sync.py" = ["F821", "B007", "E501"] # Pre-existing: style suggestions not part of dead code removal "paperforge/worker/ocr.py" = ["SIM102", "E501", "B905"] "paperforge/worker/repair.py" = ["SIM102"] "paperforge/ocr_diagnostics.py" = ["E501", "SIM105"] # Pre-existing: importability check in status.py uses try/except imports "paperforge/worker/status.py" = ["F401"] # Pre-existing: test files use patterns incompatible with strict ruff rules "tests/**" = ["E501", "E402", "SIM117", "SIM108", "F841", "B007", "SIM103", "SIM105", "SIM222", "B905"] # Pre-existing: scripts with formatting not part of this cleanup "scripts/consistency_audit.py" = ["SIM110", "SIM102"] "scripts/welcome.py" = ["E501"] "scripts/validate_setup.py" = ["E501"] [tool.ruff.format] quote-style = "double"