Skip to content

Commit b3b9baf

Browse files
committed
fix(typing): use typing extensions package on python versions under 3.11
1 parent 87ab579 commit b3b9baf

File tree

3 files changed

+118
-94
lines changed

3 files changed

+118
-94
lines changed

src/typesense/api_call.py

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
1+
2+
from __future__ import annotations
3+
14
import copy
25
import json
6+
import sys
37
import time
4-
from typing import (
5-
Any,
6-
Callable,
7-
Generic,
8-
Literal,
9-
NotRequired,
10-
TypedDict,
11-
TypeVar,
12-
Unpack,
13-
overload,
14-
)
158

169
import requests
1710
from .exceptions import (HTTPStatus0Error, ObjectAlreadyExists,
@@ -21,20 +14,34 @@
2114
from typesense.configuration import Configuration, Node
2215
from .logger import logger
2316
session = requests.session()
24-
TParams = TypeVar('TParams', bound=dict[str, Any])
25-
TBody = TypeVar('TBody', bound=dict[str, Any])
26-
TEntityDict = TypeVar('TEntityDict')
27-
2817

29-
class SessionFunctionKwargs(Generic[TParams, TBody], TypedDict):
30-
params: NotRequired[TParams | None]
31-
data: NotRequired[TBody | str]
18+
if sys.version_info >= (3, 11):
19+
import typing
20+
else:
21+
import typing_extensions as typing
22+
23+
TParams = typing.TypeVar("TParams", bound=typing.Dict[str, typing.Any])
24+
TBody = typing.TypeVar("TBody", bound=typing.Dict[str, typing.Any])
25+
TEntityDict = typing.TypeVar("TEntityDict")
26+
class SessionFunctionKwargs(typing.Generic[TParams, TBody], typing.TypedDict):
27+
"""
28+
Dictionary of keyword arguments for the session function.
29+
30+
Attributes:
31+
params (TParams | None): The request parameters.
32+
data (TBody | str): The request body.
33+
timeout (float): The timeout for the request.
34+
verify (bool): Whether to verify
35+
"""
36+
37+
params: typing.NotRequired[TParams | None]
38+
data: typing.NotRequired[TBody | str]
3239
timeout: float
3340
verify: bool
3441

3542

36-
class ApiCall(Generic[TEntityDict, TParams, TBody]):
3743
API_KEY_HEADER_NAME = 'X-TYPESENSE-API-KEY'
44+
class ApiCall(typing.Generic[TEntityDict, TParams, TBody]):
3845

3946
def __init__(self, config: Configuration):
4047
self.config = config
@@ -103,31 +110,31 @@ def get_exception(http_code: int) -> type[TypesenseClientError]:
103110
else:
104111
return TypesenseClientError
105112

106-
@overload
113+
@typing.overload
107114
def make_request(
108115
self,
109-
fn: Callable[..., requests.models.Response],
116+
fn: typing.Callable[..., requests.models.Response],
110117
endpoint: str,
111-
as_json: Literal[True],
112-
**kwargs: Unpack[SessionFunctionKwargs[TParams, TBody]],
113-
) -> TEntityDict: ...
118+
as_json: typing.Literal[True],
119+
**kwargs: typing.Unpack[SessionFunctionKwargs[TParams, TBody]],
120+
) -> TEntityDict:
114121

115-
@overload
122+
@typing.overload
116123
def make_request(
117124
self,
118-
fn: Callable[..., requests.models.Response],
125+
fn: typing.Callable[..., requests.models.Response],
119126
endpoint: str,
120-
as_json: Literal[False],
121-
**kwargs: Unpack[SessionFunctionKwargs[TParams, TBody]],
122-
) -> str: ...
127+
as_json: typing.Literal[False],
128+
**kwargs: typing.Unpack[SessionFunctionKwargs[TParams, TBody]],
129+
) -> str:
123130

124131
# Makes the actual http request, along with retries
125132
def make_request(
126133
self,
127-
fn: Callable[..., requests.models.Response],
134+
fn: typing.Callable[..., requests.models.Response],
128135
endpoint: str,
129136
as_json: bool,
130-
**kwargs: Unpack[SessionFunctionKwargs[TParams, TBody]],
137+
**kwargs: typing.Unpack[SessionFunctionKwargs[TParams, TBody]],
131138
) -> TEntityDict | str:
132139
num_tries = 0
133140
last_exception: BaseException
@@ -188,20 +195,26 @@ def normalize_params(params: TParams) -> None:
188195
elif isinstance(params[key], bool) and not params[key]:
189196
params[key] = 'false'
190197

191-
@overload
198+
@typing.overload
192199
def get(
193-
self, endpoint: str, as_json: Literal[False], params: TParams | None = None
194-
) -> str: ...
200+
self,
201+
endpoint: str,
202+
as_json: typing.Literal[False],
203+
params: TParams | None = None,
204+
) -> str:
195205

196-
@overload
206+
@typing.overload
197207
def get(
198-
self, endpoint: str, as_json: Literal[True], params: TParams | None = None
199-
) -> TEntityDict: ...
208+
self,
209+
endpoint: str,
210+
as_json: typing.Literal[True],
211+
params: TParams | None = None,
212+
) -> TEntityDict:
200213

201214
def get(
202215
self,
203216
endpoint: str,
204-
as_json: Literal[True] | Literal[False] = True,
217+
as_json: typing.Literal[True] | typing.Literal[False] = True,
205218
params: TParams | None = None,
206219
) -> TEntityDict | str:
207220
return self.make_request(
@@ -213,29 +226,29 @@ def get(
213226
verify=self.config.verify,
214227
)
215228

216-
@overload
229+
@typing.overload
217230
def post(
218231
self,
219232
endpoint: str,
220233
body: TBody,
221-
as_json: Literal[False],
234+
as_json: typing.Literal[False],
222235
params: TParams | None = None,
223-
) -> str: ...
236+
) -> str:
224237

225-
@overload
238+
@typing.overload
226239
def post(
227240
self,
228241
endpoint: str,
229242
body: TBody,
230-
as_json: Literal[True],
243+
as_json: typing.Literal[True],
231244
params: TParams | None = None,
232-
) -> TEntityDict: ...
245+
) -> TEntityDict:
233246

234247
def post(
235248
self,
236249
endpoint: str,
237250
body: TBody,
238-
as_json: Literal[True, False],
251+
as_json: typing.Literal[True, False],
239252
params: TParams | None = None,
240253
) -> str | TEntityDict:
241254
if params:

src/typesense/configuration.py

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,40 +16,46 @@
1616

1717
from __future__ import annotations
1818

19+
import sys
1920
import time
20-
from typing import Literal, NotRequired, TypedDict, Union
21+
22+
if sys.version_info >= (3, 11):
23+
import typing
24+
else:
25+
import typing_extensions as typing
26+
2127
from urllib.parse import urlparse
2228

2329
from typesense.exceptions import ConfigError
2430
from typesense.logger import logger
2531

2632

27-
class NodeConfigDict(TypedDict):
33+
class NodeConfigDict(typing.TypedDict):
2834
"""
2935
A dictionary that represents the configuration for a node in the Typesense cluster.
3036
3137
Attributes:
3238
host (str): The host name of the node.
3339
port (int): The port number of the node.
3440
path (str, optional): The path of the node.
35-
protocol (Literal['http', 'https'] | str): The protocol of the node.
41+
protocol (typing.Literal['http', 'https'] | str): The protocol of the node.
3642
"""
3743

3844
host: str
3945
port: int
40-
path: NotRequired[str]
41-
protocol: Literal['http', 'https'] | str
46+
path: typing.NotRequired[str]
47+
protocol: typing.Literal["http", "https"] | str
4248

4349

44-
class ConfigDict(TypedDict):
50+
class ConfigDict(typing.TypedDict):
4551
"""
4652
A dictionary that represents the configuration for the Typesense client.
4753
4854
Attributes:
49-
nodes (list[Union[str, NodeConfigDict]]): A list of dictionaries or URLs that
55+
nodes (list[typing.Union[str, NodeConfigDict]]): A list of dictionaries or URLs that
5056
represent the nodes in the cluster.
5157
52-
nearest_node (Union[str, NodeConfigDict]): A dictionary or URL
58+
nearest_node (typing.Union[str, NodeConfigDict]): A dictionary or URL
5359
that represents the nearest node to the client.
5460
5561
api_key (str): The API key to use for authentication.
@@ -65,23 +71,25 @@ class ConfigDict(TypedDict):
6571
6672
timeout_seconds (int, deprecated): The connection timeout in seconds.
6773
68-
master_node (Union[str, NodeConfigDict], deprecated): A dictionary or
74+
master_node (typing.Union[str, NodeConfigDict], deprecated): A dictionary or
6975
URL that represents the master node.
7076
71-
read_replica_nodes (list[Union[str, NodeConfigDict]], deprecated): A list of
77+
read_replica_nodes (list[typing.Union[str, NodeConfigDict]], deprecated): A list of
7278
dictionaries or URLs that represent the read replica nodes.
7379
"""
7480

75-
nodes: list[Union[str, NodeConfigDict]]
76-
nearest_node: NotRequired[Union[str, NodeConfigDict]]
81+
nodes: list[typing.Union[str, NodeConfigDict]]
82+
nearest_node: typing.NotRequired[typing.Union[str, NodeConfigDict]]
7783
api_key: str
78-
num_retries: NotRequired[int]
79-
interval_seconds: NotRequired[int]
80-
healthcheck_interval_seconds: NotRequired[int]
81-
verify: NotRequired[bool]
82-
timeout_seconds: NotRequired[int] # deprecated
83-
master_node: NotRequired[Union[str, NodeConfigDict]] # deprecated
84-
read_replica_nodes: NotRequired[list[Union[str, NodeConfigDict]]] # deprecated
84+
num_retries: typing.NotRequired[int]
85+
interval_seconds: typing.NotRequired[int]
86+
healthcheck_interval_seconds: typing.NotRequired[int]
87+
verify: typing.NotRequired[bool]
88+
timeout_seconds: typing.NotRequired[int] # deprecated
89+
master_node: typing.NotRequired[typing.Union[str, NodeConfigDict]] # deprecated
90+
read_replica_nodes: typing.NotRequired[
91+
list[typing.Union[str, NodeConfigDict]]
92+
] # deprecated
8593

8694

8795
class Node:
@@ -92,7 +100,7 @@ class Node:
92100
host (str): The host name of the node.
93101
port (str | int): The port number of the node.
94102
path (str): The path of the node.
95-
protocol (Literal['http', 'https'] | str): The protocol of the node.
103+
protocol (typing.Literal['http', 'https'] | str): The protocol of the node.
96104
healthy (bool): Whether the node is healthy or not.
97105
"""
98106

@@ -101,7 +109,7 @@ def __init__(
101109
host: str,
102110
port: str | int,
103111
path: str,
104-
protocol: Literal['http', 'https'] | str,
112+
protocol: typing.Literal["http", "https"] | str,
105113
) -> None:
106114
"""
107115
Initialize a Node object with the specified host, port, path, and protocol.
@@ -110,7 +118,7 @@ def __init__(
110118
host (str): The host name of the node.
111119
port (str | int): The port number of the node.
112120
path (str): The path of the node.
113-
protocol (Literal['http', 'https'] | str): The protocol of the node.
121+
protocol (typing.Literal['http', 'https'] | str): The protocol of the node.
114122
"""
115123
self.host = host
116124
self.port = port
@@ -208,8 +216,8 @@ def __init__(
208216

209217
def _handle_nearest_node(
210218
self,
211-
nearest_node: Union[str, NodeConfigDict, None],
212-
) -> Union[Node, None]:
219+
nearest_node: typing.Union[str, NodeConfigDict, None],
220+
) -> typing.Union[Node, None]:
213221
"""
214222
Handle the nearest node configuration.
215223
@@ -225,7 +233,7 @@ def _handle_nearest_node(
225233

226234
def _initialize_nodes(
227235
self,
228-
node: Union[str, NodeConfigDict],
236+
node: typing.Union[str, NodeConfigDict],
229237
) -> Node:
230238
"""
231239
Handle the initialization of a node.
@@ -286,7 +294,7 @@ def validate_required_config_fields(config_dict: ConfigDict) -> None:
286294
raise ConfigError('`api_key` is not defined.')
287295

288296
@staticmethod
289-
def validate_nodes(nodes: list[Union[str, NodeConfigDict]]) -> None:
297+
def validate_nodes(nodes: list[typing.Union[str, NodeConfigDict]]) -> None:
290298
"""
291299
Validate the nodes in the configuration dictionary.
292300
@@ -309,7 +317,7 @@ def validate_nodes(nodes: list[Union[str, NodeConfigDict]]) -> None:
309317
)
310318

311319
@staticmethod
312-
def validate_nearest_node(nearest_node: Union[str, NodeConfigDict]) -> None:
320+
def validate_nearest_node(nearest_node: typing.Union[str, NodeConfigDict]) -> None:
313321
"""
314322
Validate the nearest node in the configuration dictionary.
315323

0 commit comments

Comments
 (0)