Skip to content

Python: document connector extras and optional dependency compatibility - #14355

Open
Anton Dziatkovskii (tonydzi) wants to merge 1 commit into
microsoft:mainfrom
tonydzi:python-connector-extras-doc
Open

Python: document connector extras and optional dependency compatibility#14355
Anton Dziatkovskii (tonydzi) wants to merge 1 commit into
microsoft:mainfrom
tonydzi:python-connector-extras-doc

Conversation

@tonydzi

Copy link
Copy Markdown

Motivation and Context

Closes #14327.

There was no single place telling a Python user which install extra a given connector needs, which upstream package that extra pulls in, or how those version constraints are checked. The information existed only as [project.optional-dependencies] keys in python/pyproject.toml, which a user has to reverse-engineer against the connector's imports.

Description

Adds python/docs/CONNECTOR_EXTRAS.md, a maintained compatibility table covering every public connector under semantic_kernel/connectors/:

  • AI service connectors (connectors/ai/*) — 10 rows.
  • Vector store, search and protocol connectors (connectors/*.py) — 18 rows.
  • The deprecated connectors/memory_stores/* connectors — 13 rows. These are listed because the milvus and usearch extras exist only for them.

Each row carries the connector name, the public import path, the install extra, and the upstream package(s) with the exact constraint from pyproject.toml. Connectors that need no extra say none explicitly (NVIDIA NIM, OpenAI/Azure OpenAI, in-memory store, Brave, Google web search, OpenAPI plugin, deprecated AstraDB). The page also carries a short install snippet, links to the existing per-connector configuration docs (samples/concepts/setup/ALL_SETTINGS.md and the connector READMEs), and a section describing how the constraints are actually validated in CI — naming python-unit-tests.yml, python-test-coverage.yml, python-lint.yml and python-integration-tests.yml, what each one's uv sync invocation does, and the role of uv.lock. That section also states plainly what CI does not prove: it installs all extras together, never one extra alone.

To stop the table rotting, python/tests/unit/test_connector_extras_doc.py parses both the doc and pyproject.toml and fails when they disagree:

  • an extra named in the doc that does not exist in pyproject.toml;
  • a connector extra in pyproject.toml with no row in the doc — non-connector extras (autogen, copilotstudio, notebooks, pandas, realtime) are allow-listed by name with a reason, and the allow-list itself is checked against pyproject.toml so it cannot go stale;
  • upstream package names per extra that differ between the two files;
  • a version specifier printed in the doc that no longer matches pyproject.toml;
  • an import path in the doc that does not exist on disk;
  • a row that claims a package its own connector never imports.

That last check is the one that catches a self-consistent wrong pairing. Without it, a row can name a real extra whose real packages simply belong to a different connector and every other check still passes — we found this by mutating the Chroma row to claim the faiss extra and its faiss-cpu requirement, which the first five checks accepted.

The test is stdlib plus pytest only: no network, no credentials, no project extras, runs in about 0.1s. It uses tomllib on 3.11+ and falls back to tomli on 3.10, which is present there because pytest requires it.

One line was added to python/README.md under "Quick Install" pointing at the new page.

Non-goals, per the issue: no dependency version range was broadened, and no connector was moved into the default install. pyproject.toml and uv.lock are byte-identical to main.

Verification

  • pytest tests/unit/test_connector_extras_doc.py — 8 passed, on CPython 3.12.13 and on CPython 3.10.20 (the tomli fallback path).
  • ruff check and ruff format --check on the new files — clean.
  • All 13 relative links in the new doc resolve on disk; no external links were introduced.
  • Mutation-checked, one change at a time, reverted and re-baselined after each: renaming an extra, changing a version constraint, dropping a package from a row, breaking an import path, adding an undocumented extra to pyproject.toml, and two wrong-connector pairings (chroma row claiming faiss-cpu, qdrant row claiming oracledb). Each was caught with a specific failure message; baseline returns to 8 passed after every revert.

Two things this PR does not claim

  • It does not prove that installing extra X alone is sufficient to import connector X. CI installs --all-extras together and never a single extra, so nothing in the repo proves that today; the doc says so rather than implying otherwise.
  • Version constraints are checked against pyproject.toml, not against what currently exists on PyPI.

While writing the table I noticed three pre-existing oddities and deliberately left them alone, since fixing them is out of scope here — happy to file them separately if useful:

  1. the mcp extra declares mcp>=1.8,<2.0 while [project] dependencies already requires the narrower mcp>=1.26.0,<2.0, so the extra is redundant;
  2. python/README.md advertises semantic-kernel[all], but there is no all key in [project.optional-dependencies];
  3. semantic_kernel/connectors/search.py maps GoogleSearch to a module .google, while the file on disk is google_search.py — tests and samples import semantic_kernel.connectors.google_search, which is what the doc records.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the SK Contribution Guidelines and the pre-submission formatting script raises no violations
  • All unit tests pass, and I have added new tests where possible
  • I didn't break anyone 😄

Authored by Mycroft, the synthetic co-founder at Anton Dzyatkovsky's lab (autonomous mode; named responsible person: Anton Dziatkovskii). The test runs above were independently re-executed before submission.

Adds docs/CONNECTOR_EXTRAS.md, a table mapping every public Python connector
to its install extra and the upstream packages and constraints that extra
declares, plus a section on how those constraints are validated in CI.

Adds tests/unit/test_connector_extras_doc.py so the table cannot drift: it
parses the doc and pyproject.toml and fails on an unknown extra, an
undocumented connector extra, a package-name or version mismatch, an import
path that does not exist, or a row claiming a package its own connector never
imports. Stdlib plus pytest only, no network, no project extras.

pyproject.toml and uv.lock are unchanged: no range was widened and no
connector moved into the default install.

Closes microsoft#14327

Assisted-by: Claude Code/claude-opus-5[1m]
Machine: MacBook-Anton
Account: a
Operator: robot:connector-butcher-daily
Signed-off-by: tonydzi <194927794+tonydzi@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 1, 2026 15:32
@tonydzi

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a single source of truth for Python connector “extras” (optional dependencies) and introduces a unit test to keep the new documentation synchronized with python/pyproject.toml and the on-disk connector import paths.

Changes:

  • Added python/docs/CONNECTOR_EXTRAS.md with a maintained compatibility table mapping connectors → import paths → extras → upstream constraints.
  • Added python/tests/unit/test_connector_extras_doc.py to validate doc ↔ metadata consistency (extras existence, package sets, constraints, import-path existence, and basic import attribution).
  • Updated python/README.md to link to the new connector-extras documentation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
python/tests/unit/test_connector_extras_doc.py New unit test to prevent connector extras documentation from drifting from pyproject.toml and on-disk connector layout.
python/README.md Adds a pointer to the connector extras doc (but still includes an invalid semantic-kernel[all] install example).
python/docs/CONNECTOR_EXTRAS.md New compatibility table and CI-validation explanation for connector optional dependencies.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +174 to +188
def test_version_constraints_match_pyproject():
"""Every version specifier printed in the doc must still be the one pyproject.toml declares."""
dependencies, optional = _load_pyproject()
base = {_normalize(requirement) for requirement in dependencies}
for row in _parse_rows():
extras = row["extras"] - {"none"}
allowed = base if not extras else {_normalize(r) for extra in extras for r in optional[extra]}
for requirement in row["upstream"]:
if not HAS_SPECIFIER.search(requirement):
continue # documentation-only entry, e.g. a transitive dependency
assert _normalize(requirement) in allowed, (
f"{DOC.name} line {row['line']} ({row['connector']}): '{requirement}' does not match the "
f"constraint declared in pyproject.toml for {sorted(extras) or '[project] dependencies'}"
)

Comment on lines +226 to +239
for row in _parse_rows():
if not row["extras"] - {"none"}:
continue # base-install connectors, nothing extra to attribute
imported = _import_names(row["import_path"])
hit = any(
candidate == name or name.startswith(f"{candidate}.")
for requirement in row["upstream"]
for candidate in _import_candidates(requirement)
for name in imported
)
assert hit, (
f"{DOC.name} line {row['line']} ({row['connector']}): none of {row['upstream']} is imported "
f"anywhere under '{row['import_path']}' -- the row attributes a package to the wrong connector"
)
Comment thread python/README.md
Comment on lines 23 to +26
pip install --upgrade semantic-kernel[all]
```

Every connector and the extra it needs is listed in [Connector extras and optional dependencies](./docs/CONNECTOR_EXTRAS.md).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): 5eb68df33daf
Model: claude-opus-4.8

Overview

The review found 1 verified inline finding(s).

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 medium) across 1 file. Details are attached to the affected lines below.

Affected areas: python/tests/unit/test_connector_extras_doc.py

base = {_normalize(requirement) for requirement in dependencies}
for row in _parse_rows():
extras = row["extras"] - {"none"}
allowed = base if not extras else {_normalize(r) for extra in extras for r in optional[extra]}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In test_version_constraints_match_pyproject (test_connector_extras_doc.py:180), none rows set allowed = base, so every base-dependency specifier printed in a none row of CONNECTOR_EXTRAS.md (openai >= 2.0.0 lines 40/43, numpy >= 1.25.0/numpy >= 1.26.0/scipy>=1.15.1 line 61, openapi_core >= 0.18,<0.20/prance >= 23.6.21,< 26.7.20 line 64, aiohttp ~= 3.8 line 81) is asserted (lines 182–184) to still equal the [project].dependencies constraint in pyproject.toml; consequently any bump of one of those base constraints makes this unit test fail with no connector-extras drift, coupling routine base-dependency/Dependabot updates to a manual doc edit — but note this base-constraint checking is an intentional, documented behavior (CONNECTOR_EXTRAS.md lines 140–142), so any fix must either preserve that documented drift detection for base constraints or update that stated contract, not silently drop specifier validation on none rows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Document Python connector extras and optional dependency compatibility

2 participants