From 373daed8fa3bcbebcc5e0357ff5029f8906b4475 Mon Sep 17 00:00:00 2001 From: Stefan Bogdan Date: Tue, 29 Aug 2023 11:47:20 +0200 Subject: [PATCH] fix gh-449 --- integration/test_batch.py | 8 ++++---- integration/test_cluster.py | 14 ++++++++++++++ integration/test_schema.py | 27 ++++++++++++++++++++++++--- test/test_util.py | 12 ++++++++++++ weaviate/batch/crud_batch.py | 8 ++++---- weaviate/cluster/cluster.py | 4 +++- weaviate/schema/crud_schema.py | 8 ++++---- weaviate/util.py | 2 +- 8 files changed, 66 insertions(+), 17 deletions(-) diff --git a/integration/test_batch.py b/integration/test_batch.py index 4157169bf..2c6941631 100644 --- a/integration/test_batch.py +++ b/integration/test_batch.py @@ -86,9 +86,9 @@ def test_add_data_object(client: weaviate.Client, uuid: Optional[UUID], vector: def test_delete_objects(client: weaviate.Client): with client.batch as batch: batch.add_data_object(data_object={"name": "one"}, class_name="Test") - batch.add_data_object(data_object={"name": "two"}, class_name="Test") + batch.add_data_object(data_object={"name": "two"}, class_name="test") batch.add_data_object(data_object={"name": "three"}, class_name="Test") - batch.add_data_object(data_object={"name": "four"}, class_name="Test") + batch.add_data_object(data_object={"name": "four"}, class_name="test") batch.add_data_object(data_object={"name": "five"}, class_name="Test") with client.batch as batch: @@ -106,7 +106,7 @@ def test_delete_objects(client: weaviate.Client): with client.batch as batch: batch.delete_objects( - "Test", + "test", where={ "path": ["name"], "operator": "ContainsAny", @@ -135,7 +135,7 @@ def test_delete_objects(client: weaviate.Client): with pytest.raises(ValueError) as error: with client.batch as batch: batch.delete_objects( - "Test", + "test", where={ "path": ["name"], "operator": "ContainsAny", diff --git a/integration/test_cluster.py b/integration/test_cluster.py index e60957948..dc8dd5cad 100644 --- a/integration/test_cluster.py +++ b/integration/test_cluster.py @@ -48,6 +48,7 @@ def test_get_nodes_status_without_data(client): def test_get_nodes_status_with_data(client): """get nodes status with data""" class_name1 = "ClassA" + uncap_class_name1 = "classA" client.schema.create(schema(class_name1)) for i in range(NUM_OBJECT): client.data_object.create({"stringProp": f"object-{i}", "intProp": i}, class_name1) @@ -85,3 +86,16 @@ def test_get_nodes_status_with_data(client): assert shards[0]["class"] == class_name1 assert shards[0]["objectCount"] == NUM_OBJECT assert resp[0]["stats"]["objectCount"] == NUM_OBJECT + + resp = client.cluster.get_nodes_status(uncap_class_name1) + assert len(resp) == 1 + assert resp[0]["gitHash"] == GIT_HASH + assert resp[0]["name"] == NODE_NAME + assert len(resp[0]["shards"]) == 1 + assert resp[0]["stats"]["shardCount"] == 1 + assert resp[0]["status"] == "HEALTHY" + assert resp[0]["version"] == SERVER_VERSION + + assert shards[0]["class"] == class_name1 + assert shards[0]["objectCount"] == NUM_OBJECT + assert resp[0]["stats"]["objectCount"] == NUM_OBJECT diff --git a/integration/test_schema.py b/integration/test_schema.py index 02270b400..12de6ae6f 100644 --- a/integration/test_schema.py +++ b/integration/test_schema.py @@ -97,6 +97,7 @@ def test_schema_keys(client: weaviate.Client): def test_class_tenants(client: weaviate.Client): class_name = "MultiTenancySchemaTest" + uncap_class_name = "multiTenancySchemaTest" single_class = {"class": class_name, "multiTenancyConfig": {"enabled": True}} client.schema.delete_all() client.schema.create_class(single_class) @@ -108,17 +109,20 @@ def test_class_tenants(client: weaviate.Client): Tenant(name="Tenant3"), Tenant(name="Tenant4"), ] - client.schema.add_class_tenants(class_name, tenants) + client.schema.add_class_tenants(class_name, tenants[:2]) + client.schema.add_class_tenants(uncap_class_name, tenants[2:]) tenants_get = client.schema.get_class_tenants(class_name) assert len(tenants_get) == len(tenants) client.schema.remove_class_tenants(class_name, ["Tenant2", "Tenant4"]) - tenants_get = client.schema.get_class_tenants(class_name) - assert len(tenants_get) == 2 + client.schema.remove_class_tenants(uncap_class_name, ["Tenant1"]) + tenants_get = client.schema.get_class_tenants(uncap_class_name) + assert len(tenants_get) == 1 def test_class_tenants_activate_deactivate(client: weaviate.Client): class_name = "MultiTenancyActivateDeactivateSchemaTest" + uncap_class_name = "multiTenancyActivateDeactivateSchemaTest" single_class = {"class": class_name, "multiTenancyConfig": {"enabled": True}} client.schema.delete_all() client.schema.create_class(single_class) @@ -160,3 +164,20 @@ def test_class_tenants_activate_deactivate(client: weaviate.Client): assert tenant.activity_status == TenantActivityStatus.HOT else: raise AssertionError(f"Unexpected tenant: {tenant.name}") + + updated_tenants = [ + Tenant(activity_status=TenantActivityStatus.COLD, name="Tenant3"), + ] + client.schema.update_class_tenants(uncap_class_name, updated_tenants) + tenants_get = client.schema.get_class_tenants(uncap_class_name) + assert len(tenants_get) == len(tenants) + # below required because tenants are returned in random order by the server + for tenant in tenants_get: + if tenant.name == "Tenant1": + assert tenant.activity_status == TenantActivityStatus.COLD + elif tenant.name == "Tenant2": + assert tenant.activity_status == TenantActivityStatus.HOT + elif tenant.name == "Tenant3": + assert tenant.activity_status == TenantActivityStatus.COLD + else: + raise AssertionError(f"Unexpected tenant: {tenant.name}") diff --git a/test/test_util.py b/test/test_util.py index 0eeb5d0c3..0ae457f01 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -158,6 +158,18 @@ def test_generate_local_beacon(self): beacon["beacon"], "weaviate://localhost/fcf33178-1b5d-5174-b2e7-04a2129dd35b" ) + beacon = generate_local_beacon(uuid_lib.UUID("fcf331781b5d5174b2e704a2129dd35b"), "Test1") + self.assertTrue("beacon" in beacon) + self.assertEqual( + beacon["beacon"], "weaviate://localhost/Test1/fcf33178-1b5d-5174-b2e7-04a2129dd35b" + ) + + beacon = generate_local_beacon(uuid_lib.UUID("fcf331781b5d5174b2e704a2129dd35b"), "test2") + self.assertTrue("beacon" in beacon) + self.assertEqual( + beacon["beacon"], "weaviate://localhost/Test2/fcf33178-1b5d-5174-b2e7-04a2129dd35b" + ) + def test__get_dict_from_object(self): """ Test the `_get_dict_from_object` function. diff --git a/weaviate/batch/crud_batch.py b/weaviate/batch/crud_batch.py index 551d61d58..ce1764c55 100644 --- a/weaviate/batch/crud_batch.py +++ b/weaviate/batch/crud_batch.py @@ -1294,11 +1294,11 @@ def delete_objects( if not isinstance(class_name, str): raise TypeError(f"'class_name' must be of type str. Given type: {type(class_name)}.") if not isinstance(where, dict): - raise TypeError(f"'where' must be of type dict. Given type: {type(class_name)}.") + raise TypeError(f"'where' must be of type dict. Given type: {type(where)}.") if not isinstance(output, str): - raise TypeError(f"'output' must be of type str. Given type: {type(class_name)}.") + raise TypeError(f"'output' must be of type str. Given type: {type(output)}.") if not isinstance(dry_run, bool): - raise TypeError(f"'dry_run' must be of type bool. Given type: {type(class_name)}.") + raise TypeError(f"'dry_run' must be of type bool. Given type: {type(dry_run)}.") params = {} if self._consistency_level is not None: @@ -1308,7 +1308,7 @@ def delete_objects( payload = { "match": { - "class": class_name, + "class": _capitalize_first_letter(class_name), "where": _clean_delete_objects_where(where), }, "output": output, diff --git a/weaviate/cluster/cluster.py b/weaviate/cluster/cluster.py index ddd06bac5..e4df04b76 100644 --- a/weaviate/cluster/cluster.py +++ b/weaviate/cluster/cluster.py @@ -11,6 +11,8 @@ EmptyResponseException, ) +from ..util import _capitalize_first_letter + class Cluster: """ @@ -54,7 +56,7 @@ def get_nodes_status(self, class_name: Optional[str] = None) -> list: """ path = "/nodes" if class_name is not None: - path += "/" + class_name + path += "/" + _capitalize_first_letter(class_name) try: response = self._connection.get(path=path) diff --git a/weaviate/schema/crud_schema.py b/weaviate/schema/crud_schema.py index 61bc85d1f..0ab9c475a 100644 --- a/weaviate/schema/crud_schema.py +++ b/weaviate/schema/crud_schema.py @@ -840,7 +840,7 @@ def add_class_tenants(self, class_name: str, tenants: List[Tenant]) -> None: loaded_tenants = [tenant._to_weaviate_object() for tenant in tenants] - path = "/schema/" + class_name + "/tenants" + path = f"/schema/{_capitalize_first_letter(class_name)}/tenants" try: response = self._connection.post(path=path, weaviate_object=loaded_tenants) except RequestsConnectionError as conn_err: @@ -874,7 +874,7 @@ def remove_class_tenants(self, class_name: str, tenants: List[str]) -> None: weaviate.UnexpectedStatusCodeException If Weaviate reports a non-OK status. """ - path = "/schema/" + class_name + "/tenants" + path = f"/schema/{_capitalize_first_letter(class_name)}/tenants" try: response = self._connection.delete(path=path, weaviate_object=tenants) except RequestsConnectionError as conn_err: @@ -903,7 +903,7 @@ def get_class_tenants(self, class_name: str) -> List[Tenant]: weaviate.UnexpectedStatusCodeException If Weaviate reports a non-OK status. """ - path = "/schema/" + class_name + "/tenants" + path = f"/schema/{_capitalize_first_letter(class_name)}/tenants" try: response = self._connection.get(path=path) except RequestsConnectionError as conn_err: @@ -958,7 +958,7 @@ def update_class_tenants(self, class_name: str, tenants: List[Tenant]) -> None: weaviate.UnexpectedStatusCodeException If Weaviate reports a non-OK status. """ - path = "/schema/" + class_name + "/tenants" + path = f"/schema/{_capitalize_first_letter(class_name)}/tenants" loaded_tenants = [tenant._to_weaviate_object() for tenant in tenants] try: response = self._connection.put(path=path, weaviate_object=loaded_tenants) diff --git a/weaviate/util.py b/weaviate/util.py index 26daf0ec6..0cc865117 100644 --- a/weaviate/util.py +++ b/weaviate/util.py @@ -195,7 +195,7 @@ def generate_local_beacon( if class_name is None: return {"beacon": f"weaviate://localhost/{uuid}"} - return {"beacon": f"weaviate://localhost/{class_name}/{uuid}"} + return {"beacon": f"weaviate://localhost/{_capitalize_first_letter(class_name)}/{uuid}"} def _get_dict_from_object(object_: Union[str, dict]) -> dict: