diff --git a/integration_v3/test_authentication.py b/integration_v3/test_authentication.py index c38f6c0c2..cf64bf14b 100644 --- a/integration_v3/test_authentication.py +++ b/integration_v3/test_authentication.py @@ -121,6 +121,7 @@ def test_authentication_user_pw( """Test authentication using Resource Owner Password Credentials Grant (User + PW).""" # testing for warnings can be flaky without this as there are open SSL conections warnings.filterwarnings(action="ignore", message="unclosed", category=ResourceWarning) + warnings.filterwarnings(action="ignore", message="Dep005", category=DeprecationWarning) url = f"http://localhost:{port}" assert is_auth_enabled(url) @@ -207,6 +208,7 @@ def test_client_with_authentication_with_anon_weaviate(recwarn): """Test that we warn users when their client has auth enabled, but weaviate has only anon access.""" # testing for warnings can be flaky without this as there are open SSL conections warnings.filterwarnings(action="ignore", message="unclosed", category=ResourceWarning) + warnings.filterwarnings(action="ignore", message="Dep005", category=DeprecationWarning) url = f"http://localhost:{ANON_PORT}" assert not is_auth_enabled(url) @@ -227,6 +229,7 @@ def test_bearer_token_without_refresh(recwarn): # testing for warnings can be flaky without this as there are open SSL conections warnings.filterwarnings(action="ignore", message="unclosed", category=ResourceWarning) + warnings.filterwarnings(action="ignore", message="Dep005", category=DeprecationWarning) url = f"http://localhost:{WCS_PORT}" assert is_auth_enabled(url) diff --git a/mock_tests/conftest.py b/mock_tests/conftest.py index 1e6812273..473ae6a9a 100644 --- a/mock_tests/conftest.py +++ b/mock_tests/conftest.py @@ -1,18 +1,16 @@ import json +from concurrent import futures +import grpc import pytest +from grpc import ServicerContext +from grpc_health.v1.health_pb2 import HealthCheckResponse, HealthCheckRequest +from grpc_health.v1.health_pb2_grpc import HealthServicer, add_HealthServicer_to_server from pytest_httpserver import HTTPServer, HeaderValueMatcher from werkzeug.wrappers import Response from weaviate.connect.base import ConnectionParams, ProtocolParams -from concurrent import futures -from grpc import ServicerContext -import grpc - -from grpc_health.v1.health_pb2 import HealthCheckResponse, HealthCheckRequest -from grpc_health.v1.health_pb2_grpc import HealthServicer, add_HealthServicer_to_server - MOCK_IP = "127.0.0.1" MOCK_PORT = 23536 MOCK_PORT_GRPC = 23537 @@ -53,13 +51,13 @@ def weaviate_mock(ready_mock): @pytest.fixture(scope="function") -def weaviate_no_auth_mock(ready_mock): - ready_mock.expect_request("/v1/meta").respond_with_json({"version": "1.25"}) - ready_mock.expect_request("/v1/.well-known/openid-configuration").respond_with_response( +def weaviate_no_auth_mock(weaviate_mock): + weaviate_mock.expect_request("/v1/meta").respond_with_json({"version": "1.25"}) + weaviate_mock.expect_request("/v1/.well-known/openid-configuration").respond_with_response( Response(json.dumps({}), status=404) ) - yield ready_mock + yield weaviate_mock @pytest.fixture(scope="function") diff --git a/mock_tests/test_automatic_retries.py b/mock_tests/test_automatic_retries.py index dacc9cc34..a5bc93e0f 100644 --- a/mock_tests/test_automatic_retries.py +++ b/mock_tests/test_automatic_retries.py @@ -1,8 +1,8 @@ import json +import uuid from typing import Optional import pytest -import uuid from werkzeug.wrappers import Request, Response import weaviate @@ -283,3 +283,33 @@ def callback_print_all(results: Optional[BatchResponse]): # callback output for each object print_output, err = capfd.readouterr() assert print_output.count("\n") == n + + +def test_retries_with_tenant(weaviate_no_auth_mock): + tenant = "tenant" + first_try = True + + def handler(request: Request): + nonlocal first_try + objects = request.json["objects"] + for obj in objects: + assert obj["tenant"] == tenant + obj["deprecations"] = None + if first_try == 0: + obj["result"] = {"errors": {"error": [{"message": "I'm an error message"}]}} + first_try = False + else: + obj["result"] = {} + return Response(json.dumps(objects)) + + weaviate_no_auth_mock.expect_request("/v1/batch/objects").respond_with_handler(handler) + + client = weaviate.Client(url=MOCK_SERVER_URL) + + n = 10 + with client.batch( + weaviate_error_retries=WeaviateErrorRetryConf(number_retries=1), + ) as batch: + for i in range(n): + batch.add_data_object({"name": "test" + str(i)}, "test", uuid.uuid4(), tenant=tenant) + weaviate_no_auth_mock.check_assertions() diff --git a/weaviate/batch/crud_batch.py b/weaviate/batch/crud_batch.py index 2db3b4ab0..89d39282f 100644 --- a/weaviate/batch/crud_batch.py +++ b/weaviate/batch/crud_batch.py @@ -806,9 +806,13 @@ def _readd_objects_after_timeout( new_batch = ObjectsBatchRequest() for obj in batch_request.get_request_body()["objects"]: class_name = obj["class"] + tenant = obj.get("tenant", None) uuid = obj["id"] + params = {"tenant": tenant} if tenant is not None else None + response_head = self._connection.head( path="/objects/" + class_name + "/" + uuid, + params=params, ) if response_head.status_code == 404: @@ -823,6 +827,7 @@ def _readd_objects_after_timeout( # object might already exist and needs to be overwritten in case of an update response = self._connection.get( path="/objects/" + class_name + "/" + uuid, + params=params, ) obj_weav = _decode_json_response_dict(response, "Re-add objects") @@ -835,6 +840,7 @@ def _readd_objects_after_timeout( data_object=obj["properties"], uuid=uuid, vector=obj.get("vector", None), + tenant=tenant, ) return new_batch diff --git a/weaviate/embedded.py b/weaviate/embedded.py index 34ca7fcca..130373705 100644 --- a/weaviate/embedded.py +++ b/weaviate/embedded.py @@ -175,8 +175,8 @@ def wait_till_listening(self) -> None: def check_supported_platform() -> None: if platform.system() in ["Windows"]: raise WeaviateStartUpError( - f"{platform.system()} is not supported with Embedded. Please upvote this feature request if " - f"you want this: https://github.com/weaviate/weaviate/issues/3315" + f"""{platform.system()} is not supported with EmbeddedDB. Please upvote this feature request if you want + this: https://github.com/weaviate/weaviate/issues/3315""" # noqa: E231 ) def stop(self) -> None: diff --git a/weaviate/util.py b/weaviate/util.py index 86fa0589d..61df9a9e4 100644 --- a/weaviate/util.py +++ b/weaviate/util.py @@ -8,13 +8,13 @@ import json import os import re +import uuid as uuid_lib from enum import Enum, EnumMeta from pathlib import Path from typing import Union, Sequence, Any, Optional, List, Dict, Generator, Tuple, cast -import requests import httpx -import uuid as uuid_lib +import requests import validators from requests.exceptions import JSONDecodeError @@ -25,8 +25,8 @@ WeaviateInvalidInputError, WeaviateUnsupportedFeatureError, ) -from weaviate.warnings import _Warnings from weaviate.types import NUMBER, UUIDS, TIME +from weaviate.warnings import _Warnings PYPI_PACKAGE_URL = "https://pypi.org/pypi/weaviate-client/json" MAXIMUM_MINOR_VERSION_DELTA = 3 # The maximum delta between minor versions of Weaviate Client that will not trigger an upgrade warning. @@ -240,8 +240,10 @@ def generate_local_beacon( raise TypeError("Expected to_object_uuid of type str or uuid.UUID") if class_name is None: - return {"beacon": f"weaviate://localhost/{uuid}"} - return {"beacon": f"weaviate://localhost/{_capitalize_first_letter(class_name)}/{uuid}"} + return {"beacon": f"weaviate://localhost/{uuid}"} # noqa: E231 + return { + "beacon": f"weaviate://localhost/{_capitalize_first_letter(class_name)}/{uuid}" # noqa: E231 + } def _get_dict_from_object(object_: Union[str, dict]) -> dict: