feat(client): expose a closed property on the client facades - #1331
feat(client): expose a closed property on the client facades#1331Aryan-Pardeshi wants to merge 424 commits into
closed property on the client facades#1331Conversation
* new: add query interface tests, fix version checking * fix: add missing file
* fix: fix grpc conversion bugs for sparse and multi vectors * fix: fix mypy
* chore: Added init_options property * refactor: @Property * test: init_opts * chore: regen async client again with Py 3.10 * chore: deepcopy kwargs
* new: set idf modifier in fastembed mixin for bm models * fix: update poetry lock * fix: tmp fix, restrict pyright version * refactor: update bm model extraction, update fastembed * fix: fix list of bm models * fix: fix default bm models list value * refactoring: remove redundant import
* updated test migrate * removed second remote client * added back multiple vector test * added single multi vector * modified random_multivectors to support single vector * fix: add version check for backward compatibility tests --------- Co-authored-by: George Panchuk <george.panchuk@qdrant.tech>
* new: retry mechanism in migrate * fixed misdeletion during merging * fix: minor type hint update --------- Co-authored-by: George Panchuk <george.panchuk@qdrant.tech>
* fix: do not modify input structs in-place * fix: regen async
* fix: update poetry lock * fix: add type annotations, update poetry.lock * fix: fix local persistence tests * fix: replace del client with client.close in local mode persistence tests
…ing field (qdrant#1224) * fix: check_match() raises TypeError when MatchText applied to non-string field * tests: move non-string match test to test_nested_filter, cover MatchText and MatchTextAny --------- Co-authored-by: George Panchuk <george.panchuk@qdrant.tech>
* fix: spurious async client tests failures * skip cluster-only test when server is standalone * increase timeout for unit test performing multiple snapshot operations * clean up stale snapshots left by previous runs * fix: remove deleted methods, add/update cluster checks * fix: remove unused import * fix: remove redundant indent --------- Co-authored-by: George Panchuk <george.panchuk@qdrant.tech>
* fix: update poetry lock * fix: add type annotations, update poetry.lock * fix: fix local persistence tests * fix: replace del client with client.close in local mode persistence tests * new: update local mode values count filter behaviour
…ant#1276) Co-authored-by: Eren Ata <erena6466@gmail.com>
Co-authored-by: Hassan Zafar <hassanzafar619@gmail.com>
) * Fix local mode filters cross-matching booleans and integers Python treats bool as a subclass of int (True == 1, False == 0), but Qdrant keeps booleans and integers as distinct payload value types. Local mode compared them with a plain `==` / `in` / `isinstance(value, (int, float))`, so: - MatchValue(value=1) matched a payload of True, and MatchValue(value=True) matched a payload of 1 (same for 0 / False) - MatchAny / MatchExcept cross-matched the same way - Range matched booleans as if they were 0 / 1 The server never cross-matches these (its ValueVariants keeps Integer and Bool distinct, and booleans are not numeric for range conditions). Add a type-aware equality helper used by the value-match conditions, and exclude booleans from range checks. Adds an in-memory regression test. * Cover MatchExcept in the bool/int cross-match test MatchExcept also routes through values_match, so assert that except=[1] keeps the True payload (bool is not the integer 1). * Add isolated MatchAny and range asserts to the bool/int cross-match test Lock the single-value MatchAny path and the check_range bool guard against regressions, in addition to the existing combined-condition coverage. * fix: handle floats in cross-match local mode filters, add congruence tests --------- Co-authored-by: George Panchuk <george.panchuk@qdrant.tech>
…dropping it (qdrant#1083) (qdrant#1247) Co-authored-by: George Panchuk <george.panchuk@qdrant.tech>
* fix: fix embed paths * tests: add local inference test for complex prefetch
…on (qdrant#1260) Co-authored-by: George Panchuk <george.panchuk@qdrant.tech>
* new: 1.19.0 updates * fix: fix search params as a dict in local mode * fix: update qdrant backward compatibility version * fix: add version check to the test * fix: add version check to the test
* fix: fix nested payload local mode * test: update test data in complex filter
QdrantRemote, AsyncQdrantRemote, QdrantLocal and AsyncQdrantLocal all expose closed, but the facades did not, so checking whether a client had been closed meant reaching through the private _client attribute. close() is already public on the facade; closed now is too, forwarding to the inner client. __repr__ aside, the async mirror needs no generator change: closed is not on AsyncQdrantBase, so the transformer leaves the property sync, which is what a property has to be. Closes qdrant#1299
✅ Deploy Preview for poetic-froyo-8baba7 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughAdded public Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/test_closed.py`:
- Around line 39-53: Add a test alongside
test_async_local_client_reports_closed_state that constructs AsyncQdrantClient
with a persistent local path, asserts closed is False before awaiting close(),
then asserts closed is True afterward.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 74d2da97-798b-4c13-a976-8496641e4a33
📒 Files selected for processing (3)
qdrant_client/async_qdrant_client.pyqdrant_client/qdrant_client.pytests/test_closed.py
| async def test_async_local_client_reports_closed_state(): | ||
| client = AsyncQdrantClient(":memory:") | ||
| assert client.closed is False | ||
|
|
||
| await client.close() | ||
| assert client.closed is True | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_async_remote_client_reports_closed_state(): | ||
| client = AsyncQdrantClient("localhost", port=6333, check_compatibility=False) | ||
| assert client.closed is False | ||
|
|
||
| await client.close() | ||
| assert client.closed is True |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add asynchronous persistent-local coverage.
The tests cover AsyncQdrantClient in memory and remote modes, but not with path=.... Add the before-and-after await client.close() assertions for an asynchronous persistent-local client.
Proposed test
`@pytest.mark.asyncio`
async def test_async_local_client_reports_closed_state():
client = AsyncQdrantClient(":memory:")
assert client.closed is False
await client.close()
assert client.closed is True
+@pytest.mark.asyncio
+async def test_async_persistent_local_client_reports_closed_state(tmp_path):
+ client = AsyncQdrantClient(path=str(tmp_path / "storage"))
+ assert client.closed is False
+
+ await client.close()
+ assert client.closed is True
+
`@pytest.mark.asyncio`
async def test_async_remote_client_reports_closed_state():📝 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.
| async def test_async_local_client_reports_closed_state(): | |
| client = AsyncQdrantClient(":memory:") | |
| assert client.closed is False | |
| await client.close() | |
| assert client.closed is True | |
| @pytest.mark.asyncio | |
| async def test_async_remote_client_reports_closed_state(): | |
| client = AsyncQdrantClient("localhost", port=6333, check_compatibility=False) | |
| assert client.closed is False | |
| await client.close() | |
| assert client.closed is True | |
| async def test_async_local_client_reports_closed_state(): | |
| client = AsyncQdrantClient(":memory:") | |
| assert client.closed is False | |
| await client.close() | |
| assert client.closed is True | |
| `@pytest.mark.asyncio` | |
| async def test_async_persistent_local_client_reports_closed_state(tmp_path): | |
| client = AsyncQdrantClient(path=str(tmp_path / "storage")) | |
| assert client.closed is False | |
| await client.close() | |
| assert client.closed is True | |
| `@pytest.mark.asyncio` | |
| async def test_async_remote_client_reports_closed_state(): | |
| client = AsyncQdrantClient("localhost", port=6333, check_compatibility=False) | |
| assert client.closed is False | |
| await client.close() | |
| assert client.closed is True |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/test_closed.py` around lines 39 - 53, Add a test alongside
test_async_local_client_reports_closed_state that constructs AsyncQdrantClient
with a persistent local path, asserts closed is False before awaiting close(),
then asserts closed is True afterward.
|
Closing in favour of #1348 — same change, branched cleanly off |
Closes #1299.
QdrantRemote,AsyncQdrantRemote,QdrantLocalandAsyncQdrantLocalall expose aclosedproperty, but the two facade classes did not.close()is public on the facade, so the only way to ask whether it had been called wasclient._client.closed, which reaches through a private attribute to get at a public one.The property forwards straight to the inner client, so there is no second source of truth to drift.
Generated file
No generator change was needed here.
closedisn't onAsyncQdrantBase, so the transformer leaves it sync in the async mirror, which is what a property has to be. I ran the generator to confirm rather than assume, and its output matches what's committed.Tests
tests/test_closed.pycovers:memory:,path=and remote, sync and async, before and afterclose(), plus one case asserting the facade agrees with the inner client. All six fail withAttributeError: 'QdrantClient' object has no attribute 'closed'before the change.The remote cases pass
check_compatibility=Falseso they don't need a server on localhost.Note on #1300
I saw that #1300 covered this issue and was closed by its author before review. This is an independent implementation, written against the current
master. Happy to close mine instead if that one is coming back.