panther 4.3.4__py3-none-any.whl → 4.3.5__py3-none-any.whl
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.
- panther/__init__.py +1 -1
- panther/_utils.py +2 -8
- panther/app.py +13 -17
- panther/caching.py +14 -11
- panther/main.py +4 -6
- panther/response.py +10 -6
- {panther-4.3.4.dist-info → panther-4.3.5.dist-info}/METADATA +1 -1
- {panther-4.3.4.dist-info → panther-4.3.5.dist-info}/RECORD +12 -12
- {panther-4.3.4.dist-info → panther-4.3.5.dist-info}/LICENSE +0 -0
- {panther-4.3.4.dist-info → panther-4.3.5.dist-info}/WHEEL +0 -0
- {panther-4.3.4.dist-info → panther-4.3.5.dist-info}/entry_points.txt +0 -0
- {panther-4.3.4.dist-info → panther-4.3.5.dist-info}/top_level.txt +0 -0
panther/__init__.py
CHANGED
panther/_utils.py
CHANGED
@@ -78,15 +78,9 @@ def is_function_async(func: Callable) -> bool:
|
|
78
78
|
return bool(func.__code__.co_flags & (1 << 7))
|
79
79
|
|
80
80
|
|
81
|
-
def
|
82
|
-
"""We are ignoring packages traceback message"""
|
81
|
+
def traceback_message(exception: Exception) -> str:
|
83
82
|
tb = TracebackException(type(exception), exception, exception.__traceback__)
|
84
|
-
|
85
|
-
for t in stack:
|
86
|
-
if t.filename.find('site-packages/panther') != -1 or t.filename.find('site-packages\\panther') != -1:
|
87
|
-
tb.stack.remove(t)
|
88
|
-
_traceback = list(tb.format(chain=False))
|
89
|
-
return exception if len(_traceback) == 1 else f'{exception}\n' + ''.join(_traceback)
|
83
|
+
return ''.join(tb.format(chain=False))
|
90
84
|
|
91
85
|
|
92
86
|
def reformat_code(base_dir):
|
panther/app.py
CHANGED
@@ -34,16 +34,16 @@ logger = logging.getLogger('panther')
|
|
34
34
|
|
35
35
|
class API:
|
36
36
|
def __init__(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
self,
|
38
|
+
*,
|
39
|
+
input_model: type[ModelSerializer] | type[BaseModel] | None = None,
|
40
|
+
output_model: type[ModelSerializer] | type[BaseModel] | None = None,
|
41
|
+
auth: bool = False,
|
42
|
+
permissions: list | None = None,
|
43
|
+
throttling: Throttling | None = None,
|
44
|
+
cache: bool = False,
|
45
|
+
cache_exp_time: timedelta | int | None = None,
|
46
|
+
methods: list[Literal['GET', 'POST', 'PUT', 'PATCH', 'DELETE']] | None = None,
|
47
47
|
):
|
48
48
|
self.input_model = input_model
|
49
49
|
self.output_model = output_model
|
@@ -51,7 +51,7 @@ class API:
|
|
51
51
|
self.permissions = permissions or []
|
52
52
|
self.throttling = throttling
|
53
53
|
self.cache = cache
|
54
|
-
self.cache_exp_time = cache_exp_time
|
54
|
+
self.cache_exp_time = cache_exp_time # or config.DEFAULT_CACHE_EXP
|
55
55
|
self.methods = methods
|
56
56
|
self.request: Request | None = None
|
57
57
|
|
@@ -84,7 +84,7 @@ class API:
|
|
84
84
|
# 6. Get Cached Response
|
85
85
|
if self.cache and self.request.method == 'GET':
|
86
86
|
if cached := await get_response_from_cache(request=self.request, cache_exp_time=self.cache_exp_time):
|
87
|
-
return Response(data=cached.data, status_code=cached.status_code)
|
87
|
+
return Response(data=cached.data, headers=cached.headers, status_code=cached.status_code)
|
88
88
|
|
89
89
|
# 7. Put PathVariables and Request(If User Wants It) In kwargs
|
90
90
|
kwargs = self.request.clean_parameters(func)
|
@@ -105,11 +105,7 @@ class API:
|
|
105
105
|
|
106
106
|
# 10. Set New Response To Cache
|
107
107
|
if self.cache and self.request.method == 'GET':
|
108
|
-
await set_response_in_cache(
|
109
|
-
request=self.request,
|
110
|
-
response=response,
|
111
|
-
cache_exp_time=self.cache_exp_time
|
112
|
-
)
|
108
|
+
await set_response_in_cache(request=self.request, response=response, cache_exp_time=self.cache_exp_time)
|
113
109
|
|
114
110
|
# 11. Warning CacheExpTime
|
115
111
|
if self.cache_exp_time and self.cache is False:
|
panther/caching.py
CHANGED
@@ -8,14 +8,14 @@ import orjson as json
|
|
8
8
|
from panther.configs import config
|
9
9
|
from panther.db.connections import redis
|
10
10
|
from panther.request import Request
|
11
|
-
from panther.response import Response
|
11
|
+
from panther.response import Response
|
12
12
|
from panther.throttling import throttling_storage
|
13
13
|
from panther.utils import generate_hash_value_from_string, round_datetime
|
14
14
|
|
15
15
|
logger = logging.getLogger('panther')
|
16
16
|
|
17
17
|
caches = {}
|
18
|
-
CachedResponse = namedtuple('CachedResponse', ['data', 'status_code'])
|
18
|
+
CachedResponse = namedtuple('CachedResponse', ['data', 'headers', 'status_code'])
|
19
19
|
|
20
20
|
|
21
21
|
def api_cache_key(request: Request, cache_exp_time: timedelta | None = None) -> str:
|
@@ -46,13 +46,16 @@ async def get_response_from_cache(*, request: Request, cache_exp_time: timedelta
|
|
46
46
|
if redis.is_connected:
|
47
47
|
key = api_cache_key(request=request)
|
48
48
|
data = (await redis.get(key) or b'{}').decode()
|
49
|
-
if
|
50
|
-
return CachedResponse(
|
51
|
-
|
49
|
+
if value := json.loads(data):
|
50
|
+
return CachedResponse(
|
51
|
+
data=value[0].encode(),
|
52
|
+
headers=value[1],
|
53
|
+
status_code=value[2]
|
54
|
+
)
|
52
55
|
else:
|
53
56
|
key = api_cache_key(request=request, cache_exp_time=cache_exp_time)
|
54
|
-
if
|
55
|
-
return CachedResponse(*
|
57
|
+
if value := caches.get(key):
|
58
|
+
return CachedResponse(*value)
|
56
59
|
|
57
60
|
|
58
61
|
async def set_response_in_cache(*, request: Request, response: Response, cache_exp_time: timedelta | int) -> None:
|
@@ -63,16 +66,14 @@ async def set_response_in_cache(*, request: Request, response: Response, cache_e
|
|
63
66
|
Cache The Data In Memory
|
64
67
|
"""
|
65
68
|
|
66
|
-
cache_data: tuple[ResponseDataTypes, int] = (response.data, response.status_code)
|
67
|
-
|
68
69
|
if redis.is_connected:
|
69
70
|
key = api_cache_key(request=request)
|
70
|
-
|
71
|
+
cache_data: tuple[str, str, int] = (response.body.decode(), response.headers, response.status_code)
|
71
72
|
cache_exp_time = cache_exp_time or config.DEFAULT_CACHE_EXP
|
72
73
|
cache_data: bytes = json.dumps(cache_data)
|
73
74
|
|
74
75
|
if not isinstance(cache_exp_time, timedelta | int | NoneType):
|
75
|
-
msg = '
|
76
|
+
msg = '`cache_exp_time` should be instance of `datetime.timedelta`, `int` or `None`'
|
76
77
|
raise TypeError(msg)
|
77
78
|
|
78
79
|
if cache_exp_time is None:
|
@@ -86,6 +87,8 @@ async def set_response_in_cache(*, request: Request, response: Response, cache_e
|
|
86
87
|
|
87
88
|
else:
|
88
89
|
key = api_cache_key(request=request, cache_exp_time=cache_exp_time)
|
90
|
+
cache_data: tuple[bytes, str, int] = (response.body, response.headers, response.status_code)
|
91
|
+
|
89
92
|
caches[key] = cache_data
|
90
93
|
|
91
94
|
if cache_exp_time:
|
panther/main.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import asyncio
|
2
1
|
import contextlib
|
3
2
|
import logging
|
4
3
|
import sys
|
@@ -12,7 +11,7 @@ import orjson as json
|
|
12
11
|
import panther.logging
|
13
12
|
from panther import status
|
14
13
|
from panther._load_configs import *
|
15
|
-
from panther._utils import
|
14
|
+
from panther._utils import traceback_message, reformat_code
|
16
15
|
from panther.cli.utils import print_info
|
17
16
|
from panther.configs import config
|
18
17
|
from panther.events import Event
|
@@ -38,7 +37,7 @@ class Panther:
|
|
38
37
|
if config.AUTO_REFORMAT:
|
39
38
|
reformat_code(base_dir=config.BASE_DIR)
|
40
39
|
except Exception as e: # noqa: BLE001
|
41
|
-
logger.error(e.args[0] if isinstance(e, PantherError) else
|
40
|
+
logger.error(e.args[0] if isinstance(e, PantherError) else traceback_message(exception=e))
|
42
41
|
sys.exit()
|
43
42
|
|
44
43
|
# Print Info
|
@@ -191,8 +190,8 @@ class Panther:
|
|
191
190
|
|
192
191
|
except Exception as e: # noqa: BLE001
|
193
192
|
# All unhandled exceptions are caught here
|
194
|
-
exception =
|
195
|
-
logger.
|
193
|
+
exception = traceback_message(exception=e)
|
194
|
+
logger.error(exception)
|
196
195
|
return await self._raise(send, monitoring=monitoring)
|
197
196
|
|
198
197
|
# Call Middlewares .after()
|
@@ -226,4 +225,3 @@ class Panther:
|
|
226
225
|
await monitoring.after(status_code)
|
227
226
|
await send({'type': 'http.response.start', 'status': status_code, 'headers': headers})
|
228
227
|
await send({'type': 'http.response.body', 'body': body, 'more_body': False})
|
229
|
-
|
panther/response.py
CHANGED
@@ -43,7 +43,7 @@ class Response:
|
|
43
43
|
:param headers: should be dict of headers
|
44
44
|
:param status_code: should be int
|
45
45
|
:param pagination: instance of Pagination or None
|
46
|
-
|
46
|
+
The `pagination.template()` method will be used
|
47
47
|
"""
|
48
48
|
self.headers = headers or {}
|
49
49
|
self.pagination: Pagination | None = pagination
|
@@ -236,7 +236,6 @@ class TemplateResponse(HTMLResponse):
|
|
236
236
|
context: dict | NoneType = None,
|
237
237
|
headers: dict | NoneType = None,
|
238
238
|
status_code: int = status.HTTP_200_OK,
|
239
|
-
pagination: Pagination | NoneType = None,
|
240
239
|
):
|
241
240
|
"""
|
242
241
|
:param source: should be a string
|
@@ -244,8 +243,13 @@ class TemplateResponse(HTMLResponse):
|
|
244
243
|
:param context: should be dict of items
|
245
244
|
:param headers: should be dict of headers
|
246
245
|
:param status_code: should be int
|
247
|
-
:param pagination: instance of Pagination or None
|
248
|
-
Its template() method will be used
|
249
246
|
"""
|
250
|
-
|
251
|
-
|
247
|
+
if path:
|
248
|
+
template = config.JINJA_ENVIRONMENT.get_template(name=path)
|
249
|
+
else:
|
250
|
+
template = config.JINJA_ENVIRONMENT.from_string(source=source)
|
251
|
+
super().__init__(
|
252
|
+
data=template.render(context or {}),
|
253
|
+
headers=headers,
|
254
|
+
status_code=status_code,
|
255
|
+
)
|
@@ -1,24 +1,24 @@
|
|
1
|
-
panther/__init__.py,sha256=
|
1
|
+
panther/__init__.py,sha256=UJP3FufxNFIxwJDwS3VMJjiDNeagB0sRjhRqiRnTnWw,110
|
2
2
|
panther/_load_configs.py,sha256=tVzUB8WqwkOcsRbs1T4vhaKICPbDlXelr5h7LVdVupU,10079
|
3
|
-
panther/_utils.py,sha256=
|
4
|
-
panther/app.py,sha256=
|
3
|
+
panther/_utils.py,sha256=uufhLXT_TdiQacrcCV-Jr12ET7uqaiX2E3Y9AzbVfDQ,4109
|
4
|
+
panther/app.py,sha256=aVVoUihLMo7rofKetw95HPq2B92a-AI9KooxFpbuTec,8158
|
5
5
|
panther/authentications.py,sha256=gf7BVyQ8vXKhiumJAtD0aAK7uIHWx_snbOKYAKrYuVw,5677
|
6
6
|
panther/background_tasks.py,sha256=HBYubDIiO_673cl_5fqCUP9zzimzRgRkDSkag9Msnbs,7656
|
7
7
|
panther/base_request.py,sha256=XD2v1gLWcCKHePowRxT6_fYnS4tdKFxTLINMX0HQu8M,3880
|
8
8
|
panther/base_websocket.py,sha256=L0tiQQjg7E3462cd91PMf_SoVMMK4YiwW45yTFdTLhY,10973
|
9
|
-
panther/caching.py,sha256=
|
9
|
+
panther/caching.py,sha256=0UWg2xlTkyTKcf6rMjf-oZIE_kJWpPfpKKaDOCZxazg,4299
|
10
10
|
panther/configs.py,sha256=0VmXWFnktMGUI8X8o2xoC92872OS1G9ohAzRcvQSD2U,3329
|
11
11
|
panther/events.py,sha256=bxDqrfiNNBlvD03vEk2LDK4xbMzTMFVcgAjx2ein7mI,1158
|
12
12
|
panther/exceptions.py,sha256=7rHdJIES2__kqOStIqbHl3Uxask2lzKgLQlkZvvDwFA,1591
|
13
13
|
panther/file_handler.py,sha256=I94tpbtTVniBnnUMkFr3Eis6kPDt8sLzS5u8TzFrR5I,1323
|
14
14
|
panther/generics.py,sha256=D2ia7M4ML15kMZiuCIMpL7ZfQhMmKpqE4wCmuRE-q4Y,7233
|
15
15
|
panther/logging.py,sha256=SGgF9faQM1QmbmMPVc6m1DY-TbV329kTD8BuzGLx3I0,2073
|
16
|
-
panther/main.py,sha256=
|
16
|
+
panther/main.py,sha256=UgzsXKC1zhtBfVIDELa9axDkWPCtVVU3aAWJpYkxTOs,9075
|
17
17
|
panther/monitoring.py,sha256=y1F3c8FJlnmooM-m1nSyOTa9eWq0v1nHnmw9zz-4Kls,1314
|
18
18
|
panther/pagination.py,sha256=ANJrEF0q1nVAfD33I4nZfUUxFcETzJb01gIhbZX3HEw,1639
|
19
19
|
panther/permissions.py,sha256=9-J5vzvEKa_PITwEVQbZZv8PG2FOu05YBlD5yMrKcfc,348
|
20
20
|
panther/request.py,sha256=F9ZiAWSse7_6moAzqdoFInUN4zTKlzijh9AdU9w3Jfw,1673
|
21
|
-
panther/response.py,sha256=
|
21
|
+
panther/response.py,sha256=mzJjCKWhfDRaW4JNlIeulGymRYJbLKcs9tA7ChCu3YA,8746
|
22
22
|
panther/routings.py,sha256=1eqbjubLnUUEQRlz8mIF464ImvCMjyasiekHBtxEQoQ,6218
|
23
23
|
panther/serializer.py,sha256=5O5dypP9ys0qTKrjwaXONmOqCfDHoXY1q5ajsirFjM8,9083
|
24
24
|
panther/status.py,sha256=Gc_PnYrHfInTsZpGbqiCfDB-py1C7Rh8KMdb6Lq9Exs,3346
|
@@ -49,9 +49,9 @@ panther/panel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
49
|
panther/panel/apis.py,sha256=COsbwKZyTgyHvHYbpDfusifAH9ojMS3z1KhZCt9M-Ms,2428
|
50
50
|
panther/panel/urls.py,sha256=JiV-H4dWE-m_bfaTTVxzOxTvJmOWhyLOvcbM7xU3Bn4,240
|
51
51
|
panther/panel/utils.py,sha256=0Rv79oR5IEqalqwpRKQHMn1p5duVY5mxMqDKiA5mWx4,437
|
52
|
-
panther-4.3.
|
53
|
-
panther-4.3.
|
54
|
-
panther-4.3.
|
55
|
-
panther-4.3.
|
56
|
-
panther-4.3.
|
57
|
-
panther-4.3.
|
52
|
+
panther-4.3.5.dist-info/LICENSE,sha256=2aF1hL2aC0zRPjzUkSxJUzZbn2_uLoOkn7DHjzZni-I,1524
|
53
|
+
panther-4.3.5.dist-info/METADATA,sha256=XT3S_mACyba0AlZbjR5I4GcF0AR1ngURQXl5dCwy2Go,6695
|
54
|
+
panther-4.3.5.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
55
|
+
panther-4.3.5.dist-info/entry_points.txt,sha256=6GPxYFGuzVfNB4YpHFJvYex6iWah5_tLnirAHwj2Qsg,51
|
56
|
+
panther-4.3.5.dist-info/top_level.txt,sha256=VbBs02JGXTIoHMzsX-eLOk2MCbBZzQbLhWiYpI7xI2g,8
|
57
|
+
panther-4.3.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|