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 CHANGED
@@ -1,6 +1,6 @@
1
1
  from panther.main import Panther # noqa: F401
2
2
 
3
- __version__ = '4.3.4'
3
+ __version__ = '4.3.5'
4
4
 
5
5
 
6
6
  def version():
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 clean_traceback_message(exception: Exception) -> str:
82
- """We are ignoring packages traceback message"""
81
+ def traceback_message(exception: Exception) -> str:
83
82
  tb = TracebackException(type(exception), exception, exception.__traceback__)
84
- stack = tb.stack.copy()
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
- 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,
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, ResponseDataTypes
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 cached_value := json.loads(data):
50
- return CachedResponse(*cached_value)
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 cached_value := caches.get(key):
55
- return CachedResponse(*cached_value)
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 = '"cache_exp_time" should be instance of "datetime.timedelta" or "int" or "None"'
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 clean_traceback_message, reformat_code, check_class_type_endpoint, check_function_type_endpoint
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 clean_traceback_message(e))
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 = clean_traceback_message(exception=e)
195
- logger.critical(exception)
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
- Its template() method will be used
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
- template = config.JINJA_ENVIRONMENT.get_template(path) if path is not None else config.JINJA_ENVIRONMENT.from_string(source)
251
- super().__init__(template.render(context or {}), headers, status_code, pagination=pagination)
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: panther
3
- Version: 4.3.4
3
+ Version: 4.3.5
4
4
  Summary: Fast & Friendly, Web Framework For Building Async APIs
5
5
  Home-page: https://github.com/alirn76/panther
6
6
  Author: Ali RajabNezhad
@@ -1,24 +1,24 @@
1
- panther/__init__.py,sha256=pi--vX1J1xQHzhNFeCOc2PFlgcN6A952z5Na058Avng,110
1
+ panther/__init__.py,sha256=UJP3FufxNFIxwJDwS3VMJjiDNeagB0sRjhRqiRnTnWw,110
2
2
  panther/_load_configs.py,sha256=tVzUB8WqwkOcsRbs1T4vhaKICPbDlXelr5h7LVdVupU,10079
3
- panther/_utils.py,sha256=R1tsUde1zA5iJtk-ZvWe8hp6JaNhKgNoH2rxpdiQDMc,4449
4
- panther/app.py,sha256=e2eb4sXIaBje5vpcm4pbvvEO_sj83pLfBHCIZJFFX38,8222
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=ltuJYdjNiAaKIs3jpO5EBpL8Y6CF1vAIQqh8J_Np10g,4098
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=SnDN_aqpg5qG7jqwrb9JEiBs9bSmUUDursGuXs3FJbQ,9159
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=vcKyhpjdKNNw8iksTfGSeDO3VJ6_TgvwzIOfmHAdGIc,8794
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.4.dist-info/LICENSE,sha256=2aF1hL2aC0zRPjzUkSxJUzZbn2_uLoOkn7DHjzZni-I,1524
53
- panther-4.3.4.dist-info/METADATA,sha256=1qZpoxF1s8VPGSwg14Mq24lTKFpg4Txjl0lNHogW93o,6695
54
- panther-4.3.4.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
55
- panther-4.3.4.dist-info/entry_points.txt,sha256=6GPxYFGuzVfNB4YpHFJvYex6iWah5_tLnirAHwj2Qsg,51
56
- panther-4.3.4.dist-info/top_level.txt,sha256=VbBs02JGXTIoHMzsX-eLOk2MCbBZzQbLhWiYpI7xI2g,8
57
- panther-4.3.4.dist-info/RECORD,,
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,,