lsrestclient 3.2.2__tar.gz → 3.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,19 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lsrestclient
3
- Version: 3.2.2
3
+ Version: 3.3.1
4
4
  Summary: REST Api Client
5
5
  Author: mba
6
6
  Author-email: bartel@electronic-shop.lu
7
- Requires-Python: >=3.9,<4.0
7
+ Requires-Python: >=3.12,<4.0
8
8
  Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.9
10
- Classifier: Programming Language :: Python :: 3.10
11
- Classifier: Programming Language :: Python :: 3.11
9
+ Provides-Extra: redis
12
10
  Requires-Dist: lsjsonclasses (>=2.0.1,<3.0.0)
11
+ Requires-Dist: pydantic (>=2.11.7,<3.0.0)
12
+ Requires-Dist: pydantic-settings (>=2.10.1,<3.0.0)
13
13
  Requires-Dist: pydash (>4.0.0)
14
+ Requires-Dist: redis (>=6.4.0,<7.0.0) ; extra == "redis"
14
15
  Requires-Dist: requests (>=2.31.0,<3.0.0)
16
+ Requires-Dist: requests-cache (>=1.2.1,<2.0.0)
15
17
  Requires-Dist: webexception (>=1.0.5,<2.0.0)
16
18
  Description-Content-Type: text/markdown
17
19
 
@@ -1,23 +1,33 @@
1
1
  import os
2
+ from enum import Enum
2
3
  from typing import Optional, Dict, Any
3
4
  from unittest.mock import MagicMock
4
5
 
5
6
  import lsjsonclasses
6
7
  import requests
7
- from requests import Session
8
+ import requests_cache
9
+ from requests import Response, Session
8
10
 
9
11
  import re
10
12
 
13
+ from requests_cache import CachedSession, SQLiteCache
14
+
11
15
  from lsrestclient import (
12
16
  LsRestClientResponse,
13
17
  exceptions,
14
18
  )
15
19
  from lsrestclient.contexts.bearer_token import bearer_token_context
20
+ from lsrestclient.settings import LsRestClientSettings
16
21
 
17
22
  find_parameters_regex = re.compile("{(.*?)}")
18
23
 
19
24
 
20
- class LsRestClient(Session):
25
+ class LsRestClientBackendEnum(str, Enum):
26
+ sqlite = "sqlite"
27
+ redis = "redis"
28
+
29
+
30
+ class LsRestClient(object):
21
31
  _clients = {}
22
32
 
23
33
  @classmethod
@@ -65,8 +75,28 @@ class LsRestClient(Session):
65
75
  name: str = "default",
66
76
  headers: dict = None,
67
77
  ignore_bearer_context: bool = False,
78
+ cache: bool = False,
79
+ cache_backend: LsRestClientBackendEnum = LsRestClientBackendEnum.sqlite,
68
80
  ) -> None:
69
81
  """Class representing a REST client for JSON API."""
82
+ if cache:
83
+ if cache_backend == LsRestClientBackendEnum.redis:
84
+ settings = LsRestClientSettings()
85
+ backend = requests_cache.RedisCache(
86
+ namespace=f"lsrestclient_{name}",
87
+ host=settings.redis_host,
88
+ port=settings.redis_port,
89
+ db=settings.redis_db,
90
+ ttl=settings.redis_ttl,
91
+ ttl_offset=settings.redis_ttl_offset,
92
+ )
93
+ else:
94
+ backend = SQLiteCache(f".cache/{name}")
95
+
96
+ self._session = CachedSession(backend=backend, cache_control=True, filter_fn=self.cache_filter)
97
+
98
+ else:
99
+ self._session = Session()
70
100
 
71
101
  self._mocks = {}
72
102
  self.base_url = base_url
@@ -83,6 +113,13 @@ class LsRestClient(Session):
83
113
  super().__init__()
84
114
  self._clients[name] = self
85
115
 
116
+ def cache_filter(self, response: Response) -> bool:
117
+ settings = LsRestClientSettings()
118
+ cache_control = response.headers.get("Cache-Control")
119
+ if not cache_control and settings.insert_no_cache:
120
+ return False
121
+ return True
122
+
86
123
  @staticmethod
87
124
  def mock_name(client_name: str, method: str, url: str) -> str:
88
125
  return f"{client_name}_{method.upper()}_{url}"
@@ -203,7 +240,14 @@ class LsRestClient(Session):
203
240
 
204
241
  try:
205
242
  # noinspection PyArgumentList
206
- requests_response = requests.request(
243
+ # requests_response = requests.request(
244
+ # method.upper(),
245
+ # full_url,
246
+ # *args,
247
+ # params=params,
248
+ # **kwargs,
249
+ # )
250
+ requests_response = self._session.request(
207
251
  method.upper(),
208
252
  full_url,
209
253
  *args,
@@ -314,4 +358,3 @@ class LsRestClientTestClient(LsRestClient):
314
358
  ):
315
359
  r = self.test_client.request(method, url, *args, params=params, **kwargs)
316
360
  return LsRestClientResponse(status_code=r.status_code, content=r.content.decode("utf8"), headers=r.headers)
317
-
@@ -24,10 +24,10 @@ class LsFastApiClientBase(ABC):
24
24
  return cls._client
25
25
 
26
26
  @classmethod
27
- def register(cls, base_url: str = None) -> LsRestClient:
27
+ def register(cls, base_url: str = None, **kwargs) -> LsRestClient:
28
28
  # noinspection PyArgumentList
29
29
  log.debug(f"Registering {cls.client_name} API client at {base_url}")
30
- cls._client = LsRestClient(name=cls.client_name, base_url=base_url or cls.base_url())
30
+ cls._client = LsRestClient(name=cls.client_name, base_url=base_url or cls.base_url(), **kwargs)
31
31
  return cls._client
32
32
 
33
33
  @classmethod
@@ -1,3 +1,4 @@
1
+ import datetime
1
2
  from dataclasses import dataclass
2
3
  from typing import Optional
3
4
 
@@ -5,6 +6,7 @@ import lsjsonclasses
5
6
  import pydash
6
7
  from requests import Response
7
8
  from requests.structures import CaseInsensitiveDict
9
+ from requests_cache import CachedResponse
8
10
 
9
11
 
10
12
  @dataclass
@@ -16,6 +18,11 @@ class LsRestClientResponse:
16
18
  status_code: int
17
19
  content: str
18
20
  headers: CaseInsensitiveDict
21
+ created_at: datetime.datetime | None = None
22
+ expires: datetime.datetime | None = None
23
+ cache_key: str | None = None
24
+ revalidated: bool | None = None
25
+ from_cache: bool | None = False
19
26
 
20
27
  _json: Optional[dict] = None
21
28
 
@@ -43,11 +50,14 @@ class LsRestClientResponse:
43
50
  else:
44
51
  content = response.content.decode("utf8" if encoding is None else encoding)
45
52
 
46
- return cls(
47
- status_code=response.status_code,
48
- content=content,
49
- headers=response.headers,
50
- )
53
+ ret = cls(status_code=response.status_code, content=content, headers=response.headers)
54
+ if isinstance(response, CachedResponse):
55
+ ret.created_at = response.created_at
56
+ ret.expires = response.expires
57
+ ret.cache_key = response.cache_key
58
+ ret.revalidated = response.revalidated
59
+ ret.from_cache = response.from_cache
60
+ return ret
51
61
 
52
62
  @classmethod
53
63
  def from_dict(cls, status_code: int = 200, data: dict = None, headers: CaseInsensitiveDict = None):
@@ -0,0 +1,11 @@
1
+ from pydantic_settings import BaseSettings, SettingsConfigDict
2
+
3
+
4
+ class LsRestClientSettings(BaseSettings):
5
+ model_config = SettingsConfigDict(env_prefix="lsrestclient_")
6
+ insert_no_cache: bool = True
7
+ redis_host: str = "localhost"
8
+ redis_port: int = 6379
9
+ redis_db: int = 10
10
+ redis_ttl: bool = True
11
+ redis_ttl_offset: int = 3600
@@ -1,20 +1,31 @@
1
1
  [tool.poetry]
2
2
  name = "lsrestclient"
3
- version = "3.2.2"
3
+ version = "3.3.1"
4
4
  description = "REST Api Client"
5
5
  authors = ["mba <bartel@electronic-shop.lu>"]
6
6
  readme = "README.md"
7
7
 
8
8
  [tool.poetry.dependencies]
9
- python = "^3.9"
9
+ python = "^3.12"
10
10
  requests = "^2.31.0"
11
11
  lsjsonclasses = "^2.0.1"
12
12
  pydash = ">4.0.0"
13
13
  webexception = "^1.0.5"
14
+ requests-cache = "^1.2.1"
15
+ pydantic = "^2.11.7"
16
+ pydantic-settings = "^2.10.1"
17
+ redis = "^6.4.0"
14
18
 
15
19
  [tool.poetry.group.dev.dependencies]
16
20
  pytest = "^7.4.0"
17
21
  black = "^23.7.0"
22
+ fastapi = "^0.104.1"
23
+ uvicorn = "^0.35.0"
24
+ killport = "^1.2.0"
25
+ fastapi-lsoft = "^1.0.0"
26
+
27
+ [tool.poetry.extras]
28
+ redis = ["redis"]
18
29
 
19
30
  [build-system]
20
31
  requires = ["poetry-core"]
@@ -29,8 +40,8 @@ testpaths = [
29
40
  log_cli = true
30
41
  log_cli_level = "DEBUG"
31
42
  #log_cli_level = "INFO"
32
- log_cli_format = "[%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
33
- #log_cli_format = "[%(name)s][%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
43
+ #log_cli_format = "[%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
44
+ log_cli_format = "[%(name)s][%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
34
45
 
35
46
  [tool.black]
36
47
  line-length = 120
File without changes