diff --git a/src/typesense/client.py b/src/typesense/client.py index 19cae3a..d5b2059 100644 --- a/src/typesense/client.py +++ b/src/typesense/client.py @@ -110,7 +110,7 @@ def __init__(self, config_dict: ConfigDict) -> None: self.multi_search = MultiSearch(self.api_call) self.keys = Keys(self.api_call) self.aliases = Aliases(self.api_call) - self._analyticsV1 = AnalyticsV1(self.api_call) + self._analyticsV1: typing.Optional[AnalyticsV1] = None self.analytics = Analytics(self.api_call) self.stemming = Stemming(self.api_call) self.curation_sets = CurationSets(self.api_call) @@ -128,6 +128,8 @@ def __init__(self, config_dict: ConfigDict) -> None: category=None, ) def analyticsV1(self) -> AnalyticsV1: + if self._analyticsV1 is None: + self._analyticsV1 = AnalyticsV1(self.api_call) return self._analyticsV1 def typed_collection( diff --git a/src/typesense/collection.py b/src/typesense/collection.py index a898656..4db3431 100644 --- a/src/typesense/collection.py +++ b/src/typesense/collection.py @@ -65,8 +65,8 @@ def __init__(self, api_call: ApiCall, name: str): self.name = name self.api_call = api_call self.documents: Documents[TDoc] = Documents(api_call, name) - self._overrides = Overrides(api_call, name) - self._synonyms = Synonyms(api_call, name) + self._overrides: typing.Optional[Overrides] = None + self._synonyms: typing.Optional[Synonyms] = None @property @deprecated( @@ -74,6 +74,8 @@ def __init__(self, api_call: ApiCall, name: str): category=None, ) def synonyms(self) -> Synonyms: + if self._synonyms is None: + self._synonyms = Synonyms(self.api_call, self.name) return self._synonyms @property @@ -82,6 +84,8 @@ def synonyms(self) -> Synonyms: category=None, ) def overrides(self) -> Overrides: + if self._overrides is None: + self._overrides = Overrides(self.api_call, self.name) return self._overrides def retrieve(self) -> CollectionSchema: diff --git a/tests/client_test.py b/tests/client_test.py index 3997939..824c9bd 100644 --- a/tests/client_test.py +++ b/tests/client_test.py @@ -1,9 +1,12 @@ """Tests for the Client class.""" +import logging + from tests.fixtures.document_fixtures import Companies from tests.utils.object_assertions import assert_match_object, assert_object_lists_match from typesense.client import Client from typesense.configuration import ConfigDict +import typesense.logger as typesense_logger def test_client_init(fake_config_dict: ConfigDict) -> None: @@ -27,9 +30,7 @@ def test_client_init(fake_config_dict: ConfigDict) -> None: assert fake_client.keys.keys is not None assert fake_client.aliases assert fake_client.aliases.aliases is not None - assert fake_client.analyticsV1 - assert fake_client.analyticsV1.rules - assert fake_client.analyticsV1.rules.rules is not None + assert fake_client._analyticsV1 is None assert fake_client.operations assert fake_client.debug @@ -72,3 +73,35 @@ def test_retrieve_collection_actual_no_name( collection = actual_client.typed_collection(model=Companies) assert collection is not None + + +def test_analytics_v1_deprecation_not_logged_on_init( + fake_config_dict: ConfigDict, + caplog, +) -> None: + """Test that analytics v1 deprecation is not logged on client init.""" + typesense_logger._deprecation_warnings.clear() + caplog.set_level(logging.WARNING, logger="typesense") + + Client(fake_config_dict) + + assert "Deprecation warning:" not in caplog.text + + +def test_analytics_v1_deprecation_logged_once( + fake_config_dict: ConfigDict, + caplog, +) -> None: + """Test that analytics v1 deprecation is logged once when used.""" + typesense_logger._deprecation_warnings.clear() + caplog.set_level(logging.WARNING, logger="typesense") + + client = Client(fake_config_dict) + _ = client.analyticsV1 + _ = client.analyticsV1 + + message = ( + "Deprecation warning: AnalyticsRulesV1 is deprecated on v30+. " + "Use client.analytics instead." + ) + assert caplog.text.count(message) == 1 diff --git a/tests/collection_test.py b/tests/collection_test.py index 56c4429..5b6b0b8 100644 --- a/tests/collection_test.py +++ b/tests/collection_test.py @@ -2,6 +2,7 @@ from __future__ import annotations +import logging import time import requests_mock @@ -15,6 +16,7 @@ from typesense.collection import Collection from typesense.collections import Collections from typesense.types.collection import CollectionSchema +import typesense.logger as typesense_logger def test_init(fake_api_call: ApiCall) -> None: @@ -31,7 +33,8 @@ def test_init(fake_api_call: ApiCall) -> None: collection.api_call.config.nearest_node, fake_api_call.config.nearest_node, ) - assert collection.overrides.collection_name == "companies" + assert collection._overrides is None + assert collection._synonyms is None assert collection._endpoint_path == "/collections/companies" # noqa: WPS437 @@ -252,3 +255,42 @@ def test_actual_update( } assert_to_contain_object(response.get("fields")[0], expected.get("fields")[0]) + + +def test_deprecated_resources_not_logged_on_init( + fake_api_call: ApiCall, + caplog, +) -> None: + """Test that deprecated resources are not logged on collection init.""" + typesense_logger._deprecation_warnings.clear() + caplog.set_level(logging.WARNING, logger="typesense") + + Collection(fake_api_call, "companies") + + assert "Deprecation warning:" not in caplog.text + + +def test_deprecated_resources_logged_once_on_use( + fake_api_call: ApiCall, + caplog, +) -> None: + """Test that deprecated resources are logged once when used.""" + typesense_logger._deprecation_warnings.clear() + caplog.set_level(logging.WARNING, logger="typesense") + + collection = Collection(fake_api_call, "companies") + _ = collection.synonyms + _ = collection.synonyms + _ = collection.overrides + _ = collection.overrides + + synonyms_message = ( + "Deprecation warning: The synonyms API (collections/{collection}/synonyms) " + "is deprecated is removed on v30+. Use synonym sets (synonym_sets) instead." + ) + overrides_message = ( + "Deprecation warning: Overrides is deprecated on v30+. " + "Use client.curation_sets instead." + ) + assert caplog.text.count(synonyms_message) == 1 + assert caplog.text.count(overrides_message) == 1