Skip to content

Comments

Add release sanity check to catch pytest leakage before publish#1151

Open
sfmqrb wants to merge 1 commit intoqdrant:masterfrom
sfmqrb:fix-958-release-sanity-check
Open

Add release sanity check to catch pytest leakage before publish#1151
sfmqrb wants to merge 1 commit intoqdrant:masterfrom
sfmqrb:fix-958-release-sanity-check

Conversation

@sfmqrb
Copy link

@sfmqrb sfmqrb commented Feb 16, 2026

Summary

This PR adds a release sanity check step to the publish workflow to prevent shipping broken packages when pytest accidentally leaks into library code.

What changed

  • Added tests/release_sanity_check.py which:
    • Fails if pytest is imported in qdrant_client/** outside test modules
    • Imports package modules and fails if any module requires pytest at runtime
  • Updated .github/workflows/python-publish.yml to:
    • Build wheel
    • Create a clean virtual environment
    • Install the built wheel (without dev deps)
    • Run tests/release_sanity_check.py before publishing

Why

Issue #958 mentions multiple broken releases caused by pytest leaking into package code and only being discovered after pip install qdrant-client in a fresh environment. This check makes that failure mode visible in CI before publish.

Closes #958

@netlify
Copy link

netlify bot commented Feb 16, 2026

Deploy Preview for poetic-froyo-8baba7 ready!

Name Link
🔨 Latest commit 0d29b6c
🔍 Latest deploy log https://app.netlify.com/projects/poetic-froyo-8baba7/deploys/69928baac79ad000082102d1
😎 Deploy Preview https://deploy-preview-1151--poetic-froyo-8baba7.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link

coderabbitai bot commented Feb 16, 2026

📝 Walkthrough

Walkthrough

This pull request adds release-time sanity checks to the CI pipeline to prevent pytest from leaking into the qdrant-client package. A new workflow step is introduced in the Python publish workflow that installs the built package without development dependencies and executes a new sanity check script. The script verifies that pytest imports do not appear in library source code and that all qdrant-client submodules can be imported without requiring pytest as a runtime dependency.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a release sanity check to prevent pytest leakage before publishing packages.
Description check ✅ Passed The description is well-detailed and directly related to the changeset, explaining what was added, why it was needed, and how it addresses the issue.
Linked Issues check ✅ Passed The PR fully addresses issue #958 by implementing a release sanity check in CI to detect pytest leakage before publishing, matching the exact requirement stated.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the release sanity check requirement; no unrelated modifications or feature creep detected in the workflow or test files.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into master

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tests/release_sanity_check.py`:
- Around line 54-58: The module filter in the pkgutil.walk_packages loop (using
module_info / name) only excludes names containing ".tests" or ending with
".conftest" and can still include submodules whose final name component is
prefixed with "test_" (e.g., qdrant_client.pkg.test_foo); update the condition
in the loop to also skip any module whose last dotted component starts with
"test_" (parse name.split(".")[-1] or use name.rsplit(".", 1)[-1]) so the
runtime import check mirrors the source scanner behavior.
🧹 Nitpick comments (2)
tests/release_sanity_check.py (1)

46-69: Consider logging silently-swallowed exceptions for debuggability.

Lines 67-69: The bare except Exception: pass is intentional (targeting only pytest leakage), but when a non-pytest import fails, silently swallowing it makes CI debugging harder. A one-line print/warning would help operators diagnose unexpected failures without changing the pass/fail semantics.

Also, line 48: the # noqa: F401 is flagged by Ruff as unnecessary (the F401 rule isn't enabled). Removing it keeps the file clean.

Proposed changes
-        import qdrant_client  # noqa: F401
+        import qdrant_client
         except Exception:
-            # Ignore other runtime side effects; this check targets pytest leakage.
-            pass
+            # Ignore other runtime side effects; this check targets pytest leakage.
+            print(f"  ⚠ Skipping '{name}': {exc!r}")

Note: you'd need to capture the exception to print it:

-        except Exception:
+        except Exception as exc:
.github/workflows/python-publish.yml (1)

42-42: The sanity script's source check depends on CWD being the repo root.

check_no_pytest_import_in_library_sources() uses Path("qdrant_client") as a relative path. This works because the default working directory in GitHub Actions is the checkout root. If the working directory ever changes (e.g., via a working-directory: key on this step), the source check would silently find zero files and pass vacuously. A small guard in the script (e.g., asserting the path exists) would harden this.

Proposed guard in release_sanity_check.py

Add at the top of check_no_pytest_import_in_library_sources():

 def check_no_pytest_import_in_library_sources() -> None:
     root = Path("qdrant_client")
+    if not root.is_dir():
+        fail(f"Source directory '{root}' not found (wrong working directory?)")
     offenders: list[str] = []

Comment on lines +54 to +58
for module_info in pkgutil.walk_packages(qc.__path__, prefix="qdrant_client."):
name = module_info.name

# Never import tests in this sanity check.
if ".tests" in name or name.endswith(".conftest"):
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Test-module filter could miss test_-prefixed submodules during walk.

Line 58 skips modules where ".tests" appears in the dotted name or the name ends with ".conftest". However, it doesn't skip test_-prefixed module names (e.g., qdrant_client.some_pkg.test_foo), while the source scanner on line 30 does skip files starting with test_. This inconsistency could cause the runtime check to attempt importing a test module that the source check would have excluded.

Proposed fix
         # Never import tests in this sanity check.
-        if ".tests" in name or name.endswith(".conftest"):
+        parts = name.split(".")
+        if ".tests" in name or name.endswith(".conftest") or parts[-1].startswith("test_"):
             continue
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for module_info in pkgutil.walk_packages(qc.__path__, prefix="qdrant_client."):
name = module_info.name
# Never import tests in this sanity check.
if ".tests" in name or name.endswith(".conftest"):
for module_info in pkgutil.walk_packages(qc.__path__, prefix="qdrant_client."):
name = module_info.name
# Never import tests in this sanity check.
parts = name.split(".")
if ".tests" in name or name.endswith(".conftest") or parts[-1].startswith("test_"):
continue
🤖 Prompt for AI Agents
In `@tests/release_sanity_check.py` around lines 54 - 58, The module filter in the
pkgutil.walk_packages loop (using module_info / name) only excludes names
containing ".tests" or ending with ".conftest" and can still include submodules
whose final name component is prefixed with "test_" (e.g.,
qdrant_client.pkg.test_foo); update the condition in the loop to also skip any
module whose last dotted component starts with "test_" (parse
name.split(".")[-1] or use name.rsplit(".", 1)[-1]) so the runtime import check
mirrors the source scanner behavior.

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.

Add release sanity check to CI

1 participant