Skip to content

Commit 229b4af

Browse files
tsmith023dirkkul
andauthored
Refactor to separate sync and async connections (#1594)
* Commit working changes (bypassed pre-commit) * Push non-functional progress (will fail CI) * Add non-functional backup refactoring * Add non-functional tenants refactoring * Add non-functional config refactoring * Achieve working functionality for everything besides batch * Merge dev/1.30 * Fix import * Comment out redundant test * Fix return types in query executor * Fix failing backups tests * Refactor batch to use `ConnectionSync` and `ThreadPoolExecutor` * Remove redundant event loop code * Fix event loop import in syncify, rename convert_new to convert * Fix backups executor, ensure backup tests run serially * Fix typo * Fix deprecated `get_assigned_roles` * Fix auth refactoring to pass the tests * Fix sync grpc exception handling to pass mock tests * Fix capitalisation of delete for 1.24 * Reduce boilerplate necessary in `ConnectionX` classes * Fix missing final raise * Fix docstring inheritance for client.debug as example * Introduce new decorator to generate methods from base abstract class * Migrate users namespace to use impl.generate * Migrate rbac namespace to use impl.generate * Refactor collection.data to use impl.generate * Migrate collection.tenants to impl.generate * Migration collection.{backups,cluster,config} to impl.generate * Complete client.backups impl.generate migration * Migrate collection.{generate,query} to use impl.generate * Migrate collection.aggregate to impl.generate pattern * Remove syncify code * Update pyright in CI and remove mypy * Fix outstanding bugs and migration client to impl.generate * Fix imports of backup * Fix more backup import issues * Fix typo in new dev/1.30 code * Make backup easier * Second try * Fix typing errprs * Remove composition of executor completely * Migrate rest of codebase to inheriting from `_Executor` and new `impl.generate` functinoality * Align executor and interface surfaces * Fix backup inheritance and rename/move wrapping decorators * Fix default args in users executor * Remove `_XBase` classes by making executors generic on `ConnectionType` * Simplify semantics of importing from `connect.executor` * Add QA ignores for flake8 in CI * Fix inheritance in interface * Respond to review * Tidy up import paths and remove `_WeaviateClientBase` * Fix default arg for `revoke_key` in `deactivate` * Add journey test for gevent+wsgi usage, add back litestar test * Fix breaking public imports from .users/.backups reducing diff * Have `delete_many` use specific grpc class rather than custom impl * Decrease diff in tests * Add changelog for refactor --------- Co-authored-by: Dirk Kulawiak <dirk@semi.technology>
1 parent 5e4b879 commit 229b4af

190 files changed

Lines changed: 9271 additions & 6829 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/main.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,9 @@ jobs:
6565
python-version: ${{ matrix.version }}
6666
cache: 'pip' # caching pip dependencies
6767
- run: pip install -r requirements-devel.txt
68-
- name: Run mypy
69-
run: mypy --config-file ./pyproject.toml --warn-unused-ignores --python-version ${{matrix.version}} ${{ matrix.folder }}
7068
- uses: jakebailey/pyright-action@v2
7169
with:
72-
version: 1.1.347
70+
version: 1.1.398
7371

7472
unit-tests:
7573
name: Run Unit Tests
@@ -169,7 +167,7 @@ jobs:
169167
run: pytest -n auto --dist loadgroup -v --cov --cov-report=term-missing --cov=weaviate --cov-report xml:coverage-integration.xml integration
170168
- name: Run integration tests without auth secrets (for forks)
171169
if: ${{ github.event.pull_request.head.repo.fork }}
172-
run: pytest -v --cov --cov-report=term-missing --cov=weaviate --cov-report xml:coverage-integration.xml integration
170+
run: pytest -n auto --dist loadgroup -v --cov --cov-report=term-missing --cov=weaviate --cov-report xml:coverage-integration.xml integration
173171
- name: Archive code coverage results
174172
if: matrix.versions.py == '3.10' && (github.ref_name != 'main')
175173
uses: actions/upload-artifact@v4

.pre-commit-config.yaml

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,6 @@ repos:
3636
]
3737
files: '^weaviate/collections'
3838

39-
- repo: local
40-
hooks:
41-
- id: mypy
42-
name: mypy
43-
entry: ./run-mypy.sh
44-
language: python
45-
language_version: "3.12"
46-
# use require_serial so that script
47-
# is only called once per commit
48-
require_serial: true
49-
# Print the number of files as a sanity-check
50-
verbose: true
51-
5239
- repo: local
5340
hooks:
5441
- id: pyright
@@ -57,4 +44,4 @@ repos:
5744
language: node
5845
pass_filenames: false
5946
types: [python]
60-
additional_dependencies: [pyright@1.1.364]
47+
additional_dependencies: [pyright@1.1.398]

docs/changelog.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Changelog
22
=========
33

4+
Version 4.13.0
5+
--------------
6+
This minor version provides a complete top-down refactor of the underlying transport for the sync and async clients.
7+
- Introduction of a dependency injection system whereby the sync/async connections are injected into each client independently thereby removing their cross-dependency.
8+
- Removal of the ``event_loop.py`` file and all logic surrounding its usage by the sync client.
9+
- Refactoring of the batching algorithm to use blocking threads with a sync connection, rather than the event loop sidecar thread.
10+
11+
412
Version 4.12.1
513
--------------
614
This patch version includes:

integration/test_auth.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ def test_client_with_authentication_with_anon_weaviate() -> None:
137137
with pytest.warns(UserWarning) as recwarn:
138138
with weaviate.connect_to_local(auth_credentials=auth) as client:
139139
client.collections.list_all()
140+
if len(recwarn) > 1:
141+
for rwarning in recwarn.list:
142+
print(rwarning.message)
140143
assert len(recwarn) == 1
141144
assert str(recwarn.list[0].message).startswith("Auth001")
142145

integration/test_backup_v4.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def test_backup_and_restore_with_collection(
356356

357357
conf_create: Optional[wvc.backup.BackupConfigCreate] = None
358358
conf_restore: Optional[wvc.backup.BackupConfigRestore] = None
359-
backup_location: Optional[wvc.backup.BackupLocation] = None
359+
backup_location: Optional[wvc.backup.BackupLocationType] = None
360360
if dynamic_backup_location:
361361
if client._connection._weaviate_version.is_lower_than(1, 27, 2):
362362
pytest.skip("Cancel backups is only supported from 1.27.2")
@@ -505,7 +505,7 @@ def test_cancel_backup(
505505
if client._connection._weaviate_version.is_lower_than(1, 24, 25):
506506
pytest.skip("Cancel backups is only supported from 1.24.25")
507507

508-
backup_location: Optional[wvc.backup.BackupLocation] = None
508+
backup_location: Optional[wvc.backup.BackupLocationType] = None
509509
if dynamic_backup_location:
510510
if client._connection._weaviate_version.is_lower_than(1, 27, 2):
511511
pytest.skip("Cancel backups is only supported from 1.27.2")

integration/test_client_debug.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
from integration.conftest import ClientFactory, CollectionFactory
1+
import pytest
2+
from integration.conftest import (
3+
AsyncClientFactory,
4+
AsyncCollectionFactory,
5+
ClientFactory,
6+
CollectionFactory,
7+
)
28

39
from weaviate.classes.config import DataType, Property
410
from weaviate.classes.debug import DebugRESTObject
@@ -22,6 +28,27 @@ def test_get_object_single_node(
2228
assert debug_obj is None
2329

2430

31+
@pytest.mark.asyncio
32+
async def test_get_object_single_node_async(
33+
async_client_factory: AsyncClientFactory, async_collection_factory: AsyncCollectionFactory
34+
) -> None:
35+
client = await async_client_factory()
36+
collection = await async_collection_factory(
37+
properties=[Property(name="name", data_type=DataType.TEXT)]
38+
)
39+
40+
uuid = await collection.data.insert({"name": "John Doe"})
41+
42+
debug_obj = await client.debug.get_object_over_rest(collection.name, uuid)
43+
assert debug_obj is not None
44+
assert isinstance(debug_obj, DebugRESTObject)
45+
assert str(debug_obj.uuid) == str(uuid)
46+
47+
non_existant_uuid = "00000000-0000-0000-0000-000000000000"
48+
debug_obj = await client.debug.get_object_over_rest(collection.name, non_existant_uuid)
49+
assert debug_obj is None
50+
51+
2552
def test_get_object_multi_node(
2653
client_factory: ClientFactory, collection_factory: CollectionFactory
2754
) -> None:

integration/test_collection_batch_delete.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
)
2020
from weaviate.collections.classes.internal import ReferenceToMulti
2121
from weaviate.collections.classes.tenants import Tenant
22+
from weaviate.classes.config import ConsistencyLevel
2223
from weaviate.exceptions import (
2324
WeaviateQueryException,
2425
)
@@ -633,3 +634,26 @@ def test_delete_by_time_metadata_with_ref(
633634
assert len(source) == 1
634635
assert source.query.fetch_object_by_id(uuid=uuid_source1) is not None
635636
assert source.query.fetch_object_by_id(uuid=uuid_source2) is None
637+
638+
639+
def test_delete_many_with_consistency_level(
640+
collection_factory: CollectionFactory,
641+
) -> None:
642+
collection = collection_factory(
643+
ports=(8087, 50058),
644+
properties=[
645+
Property(name="text", data_type=DataType.TEXT),
646+
Property(name="int", data_type=DataType.INT),
647+
],
648+
).with_consistency_level(ConsistencyLevel.ALL)
649+
collection.data.insert_many(
650+
[
651+
DataObject(properties={"int": 10}, uuid=UUID1),
652+
DataObject(properties={"text": "I am ageless"}, uuid=UUID2),
653+
]
654+
)
655+
assert len(collection.query.fetch_objects().objects) == 2
656+
657+
collection.data.delete_many(where=Filter.by_id().equal(UUID1))
658+
objects = collection.query.fetch_objects().objects
659+
assert len(objects) == 1

integration/test_rbac.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616
NodesPermissionOutput,
1717
TenantsPermissionOutput,
1818
UsersPermissionOutput,
19+
UserTypes,
1920
)
2021
from _pytest.fixtures import SubRequest
2122

22-
from weaviate.users.users import UserTypes
23-
2423
RBAC_PORTS = (8092, 50063)
2524
RBAC_AUTH_CREDS = Auth.api_key("admin-key")
2625

journey_tests/gunicorn/wsgi.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from typing import List
2+
3+
from flask import Flask, g
4+
5+
from journey_tests.journeys import SyncJourneys
6+
7+
app = Flask(__name__)
8+
9+
10+
def get_sync_client() -> SyncJourneys:
11+
if "sync" not in g:
12+
g.sync = SyncJourneys.use()
13+
return g.sync
14+
15+
16+
@app.route("/sync-in-sync")
17+
def sync() -> List[dict]:
18+
return get_sync_client().simple()
19+
20+
21+
if __name__ == "__main__":
22+
app.run(debug=False, host="0.0.0.0")

0 commit comments

Comments
 (0)