diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93f44ac7..6cb4563d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -149,6 +149,16 @@ jobs: - run: pip install mypy==2.4.0 types-PyYAML types-jsonschema - name: mypy run: mypy + # Dependency hygiene, config in [tool.deptry] of pyproject.toml: an import + # not declared (DEP001), a runtime dependency never imported (DEP002), an + # import that only resolves through another package's dependencies (DEP003), + # a dev-extra tool imported by the package (DEP004). Here, not in `static`: + # deptry maps import names to packages through the installed lock. + - run: pip install deptry==0.25.1 + if: ${{ !cancelled() }} + - name: deptry + if: ${{ !cancelled() }} + run: deptry . test: name: Tests (py${{ matrix.python-version }}) diff --git a/dokimi/CONTRIBUTING.md b/dokimi/CONTRIBUTING.md index 1ef0847a..66bb38d0 100644 --- a/dokimi/CONTRIBUTING.md +++ b/dokimi/CONTRIBUTING.md @@ -63,6 +63,7 @@ the same checks CI runs are: ```bash ruff check . # lint mypy # type check (config in pyproject.toml) +deptry . # declared deps match the imports ([tool.deptry]) python -m dokimi.schema_check benchmarks/spec.v1.yaml # validate the benchmark spec python -m dokimi.config_check # registry drift check pytest # tests (offline: connecting off loopback fails the test) @@ -103,6 +104,13 @@ CI additionally holds a PR to: a list). A new page goes in two places: the `docs/README.md` index (`tests/test_docs_links.py` checks it) and `nav:` in `mkdocs.yml` (the build fails on a page missing from it). `mkdocs serve` previews the site. +- **Dependencies match the imports** — `deptry .` (config in `[tool.deptry]` of + `pyproject.toml`). A third-party module the package, `cli.py` or `scripts/` + imports is declared in `[project.dependencies]` and `requirements.txt` (or an + extra), even when another dependency already pulls it in; a runtime dependency + nothing imports is dropped; the `dev` extra's tools are never imported by the + package. A dependency that is declared only to cap a transitive version gets a + `per_rule_ignores` entry with the reason. - **Workflow lint** — `zizmor --offline --min-severity medium .github/workflows` when you edit a workflow. - **Changelog fragment** — a PR that changes the package (`dokimi/`) adds one to diff --git a/dokimi/changelog.d/20261018_120000_napetrov_ci-deptry.md b/dokimi/changelog.d/20261018_120000_napetrov_ci-deptry.md new file mode 100644 index 00000000..441a9971 --- /dev/null +++ b/dokimi/changelog.d/20261018_120000_napetrov_ci-deptry.md @@ -0,0 +1,9 @@ +### Changed + +- **Install dependencies follow the imports** — `pip install dokimi` no longer + installs `beautifulsoup4` (and its `soupsieve`), which nothing imports, and no + longer lists `anthropic` itself: it still comes in through + `langchain-anthropic`. `langchain-openai` and `langchain-core`, which + `eval ragas` imports, are now declared (`>=1.0,<2`) instead of arriving only + through `ragas`. Code that imported `bs4` from dokimi's environment installs it + itself. diff --git a/dokimi/pyproject.toml b/dokimi/pyproject.toml index b13d0fbb..6ce437c2 100644 --- a/dokimi/pyproject.toml +++ b/dokimi/pyproject.toml @@ -32,16 +32,16 @@ dependencies = [ "httpx>=0.27.0", "numpy>=1.24.0", "scipy>=1.11.0", - "beautifulsoup4>=4.12.0", "PyGithub>=2.1.0", "ragas>=0.3.0,<0.4", # Every ragas release imports langchain_community.chat_models.vertexai, which 0.4.2 removed. "langchain-community<0.4.2", - # eval ragas wraps the judge in ChatAnthropic for the anthropic provider. + # eval ragas wraps the judge in ChatOpenAI or ChatAnthropic, typed as langchain-core's BaseChatModel. "langchain-anthropic>=1.0,<2", + "langchain-openai>=1.0,<2", + "langchain-core>=1.0,<2", "datasets>=2.20,<6", "openai>=1.51,<3", - "anthropic~=1.12", ] [project.optional-dependencies] @@ -108,6 +108,26 @@ md_header_level = "2" entry_title_template = "[{{ version }}] — {{ date.strftime('%Y-%m-%d') }}" version = "literal: pyproject.toml: project.version" +# Dependency hygiene (deptry, CI's typecheck job): every third-party import in +# the package, cli.py and scripts/ is declared in [project.dependencies] or an +# extra, imported directly rather than through another package's dependencies, +# and every declared runtime dependency is imported. Run from dokimi/ in an env +# with the lock installed, so import names come from the installed metadata. +# tests/ is skipped (deptry's default exclude): the test deps live in +# requirements-test.txt and the dev extra. +[tool.deptry] +extend_exclude = [ + # The docs build's hooks: their deps are requirements-docs.txt, not the wheel's. + "scripts/docs", +] +# Tools in the dev extra (pytest and plugins, ruff, mypy, scriv), never imported by +# the package. A dev dep imported from the package is DEP004. +optional_dependencies_dev_groups = ["dev"] + +[tool.deptry.per_rule_ignores] +# Declared only to cap the version ragas resolves (see the comment in [project]). +DEP002 = ["langchain-community"] + [tool.ruff] line-length = 100 target-version = "py311" diff --git a/dokimi/requirements.lock.txt b/dokimi/requirements.lock.txt index 682b3543..2539cc95 100644 --- a/dokimi/requirements.lock.txt +++ b/dokimi/requirements.lock.txt @@ -15,9 +15,7 @@ annotated-doc==0.0.5 annotated-types==0.8.0 # via pydantic anthropic==1.13.0 - # via - # -r requirements.txt - # langchain-anthropic + # via langchain-anthropic anyio==4.15.1 # via # anthropic @@ -32,8 +30,6 @@ attrs==26.1.0 # aiohttp # jsonschema # referencing -beautifulsoup4==4.15.0 - # via -r requirements.txt boto3==1.43.109 # via litellm botocore==1.43.109 @@ -200,6 +196,7 @@ langchain-community==0.4.1 # ragas langchain-core==1.6.7 # via + # -r requirements.txt # langchain # langchain-anthropic # langchain-classic @@ -212,7 +209,9 @@ langchain-core==1.6.7 # langgraph-sdk # ragas langchain-openai==1.6.7 - # via ragas + # via + # -r requirements.txt + # ragas langchain-protocol==0.0.19 # via # langchain-core @@ -446,8 +445,6 @@ sniffio==1.3.1 # anthropic # langsmith # openai -soupsieve==2.10 - # via beautifulsoup4 sqlalchemy==2.1.4 # via # langchain-classic @@ -486,7 +483,6 @@ typing-extensions==4.16.0 # aiosignal # anthropic # anyio - # beautifulsoup4 # httpx2 # huggingface-hub # langchain-core diff --git a/dokimi/requirements.txt b/dokimi/requirements.txt index 7f03e616..1fbabe70 100644 --- a/dokimi/requirements.txt +++ b/dokimi/requirements.txt @@ -4,16 +4,16 @@ ragas>=0.3.0,<0.4 # Every ragas release imports langchain_community.chat_models.vertexai, which 0.4.2 removed. langchain-community<0.4.2 -# eval ragas wraps the judge in ChatAnthropic for the anthropic provider. +# eval ragas wraps the judge in ChatOpenAI or ChatAnthropic, typed as langchain-core's BaseChatModel. langchain-anthropic>=1.0,<2 +langchain-openai>=1.0,<2 +langchain-core>=1.0,<2 datasets>=2.20,<6 openai>=1.51,<3 -anthropic~=1.12 PyYAML>=6.0.1,<7 jsonschema>=4.20,<5 litellm>=1.105.0 httpx>=0.27.0 PyGithub>=2.1.0 -beautifulsoup4>=4.12.0 numpy>=1.24.0 scipy>=1.11.0