diff --git a/meilisearch/_httprequests.py b/meilisearch/_httprequests.py index 0304693c..1fddb837 100644 --- a/meilisearch/_httprequests.py +++ b/meilisearch/_httprequests.py @@ -1,7 +1,8 @@ from __future__ import annotations import json -from typing import Any, Callable, Dict, List, Optional, Union +from functools import lru_cache +from typing import Any, Callable, Dict, List, Optional, Tuple, Union import requests @@ -19,7 +20,7 @@ def __init__(self, config: Config) -> None: self.config = config self.headers = { "Authorization": f"Bearer {self.config.api_key}", - "User-Agent": qualified_version(), + "User-Agent": _build_user_agent(config.client_agents), } def send_request( @@ -107,3 +108,12 @@ def __validate(request: requests.Response) -> Any: return HttpRequests.__to_json(request) except requests.exceptions.HTTPError as err: raise MeilisearchApiError(str(err), request) from err + + +@lru_cache(maxsize=1) +def _build_user_agent(client_agents: Optional[Tuple[str]] = None) -> str: + user_agent = qualified_version() + if not client_agents: + return user_agent + + return f"{user_agent};{';'.join(client_agents)}" diff --git a/meilisearch/client.py b/meilisearch/client.py index d5b6ae62..a926c1ae 100644 --- a/meilisearch/client.py +++ b/meilisearch/client.py @@ -8,7 +8,7 @@ import hmac import json import re -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Tuple, Union from urllib import parse from meilisearch._httprequests import HttpRequests @@ -29,7 +29,11 @@ class Client: """ def __init__( - self, url: str, api_key: Optional[str] = None, timeout: Optional[int] = None + self, + url: str, + api_key: Optional[str] = None, + timeout: Optional[int] = None, + client_agents: Optional[Tuple[str]] = None, ) -> None: """ Parameters @@ -39,7 +43,7 @@ def __init__( api_key: The optional API key for Meilisearch """ - self.config = Config(url, api_key, timeout=timeout) + self.config = Config(url, api_key, timeout=timeout, client_agents=client_agents) self.http = HttpRequests(self.config) diff --git a/meilisearch/config.py b/meilisearch/config.py index b2d1a87e..24a2fe85 100644 --- a/meilisearch/config.py +++ b/meilisearch/config.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Optional +from typing import Optional, Tuple class Config: @@ -35,7 +35,11 @@ class Paths: swap = "swap-indexes" def __init__( - self, url: str, api_key: Optional[str] = None, timeout: Optional[int] = None + self, + url: str, + api_key: Optional[str] = None, + timeout: Optional[int] = None, + client_agents: Optional[Tuple[str]] = None, ) -> None: """ Parameters @@ -49,4 +53,5 @@ def __init__( self.url = url self.api_key = api_key self.timeout = timeout + self.client_agents = client_agents self.paths = self.Paths() diff --git a/tests/client/test_http_requests.py b/tests/client/test_http_requests.py index b9f9749f..7093aa69 100644 --- a/tests/client/test_http_requests.py +++ b/tests/client/test_http_requests.py @@ -11,3 +11,20 @@ def test_get_headers_from_http_requests_instance(): assert http.headers["Authorization"] == f"Bearer {MASTER_KEY}" assert http.headers["User-Agent"] == qualified_version() + + +def test_get_headers_with_multiple_user_agent(): + """Tests getting defined headers from instance in HttpRequests.""" + config = Config( + BASE_URL, + MASTER_KEY, + timeout=None, + client_agents=("Meilisearch Package1 (v1.1.1)", "Meilisearch Package2 (v2.2.2)"), + ) + http = HttpRequests(config=config) + + assert http.headers["Authorization"] == f"Bearer {MASTER_KEY}" + assert ( + http.headers["User-Agent"] + == qualified_version() + ";Meilisearch Package1 (v1.1.1);Meilisearch Package2 (v2.2.2)" + )