panther 5.0.0b2__py3-none-any.whl → 5.0.0b4__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.
Files changed (56) hide show
  1. panther/__init__.py +1 -1
  2. panther/_load_configs.py +46 -37
  3. panther/_utils.py +49 -34
  4. panther/app.py +96 -97
  5. panther/authentications.py +97 -50
  6. panther/background_tasks.py +98 -124
  7. panther/base_request.py +16 -10
  8. panther/base_websocket.py +8 -8
  9. panther/caching.py +16 -80
  10. panther/cli/create_command.py +17 -16
  11. panther/cli/main.py +1 -1
  12. panther/cli/monitor_command.py +11 -6
  13. panther/cli/run_command.py +5 -71
  14. panther/cli/template.py +7 -7
  15. panther/cli/utils.py +58 -69
  16. panther/configs.py +70 -72
  17. panther/db/connections.py +18 -24
  18. panther/db/cursor.py +0 -1
  19. panther/db/models.py +24 -8
  20. panther/db/queries/base_queries.py +2 -5
  21. panther/db/queries/mongodb_queries.py +17 -20
  22. panther/db/queries/pantherdb_queries.py +1 -1
  23. panther/db/queries/queries.py +26 -8
  24. panther/db/utils.py +1 -1
  25. panther/events.py +25 -14
  26. panther/exceptions.py +2 -7
  27. panther/file_handler.py +1 -1
  28. panther/generics.py +11 -8
  29. panther/logging.py +2 -1
  30. panther/main.py +12 -13
  31. panther/middlewares/cors.py +67 -0
  32. panther/middlewares/monitoring.py +5 -3
  33. panther/openapi/urls.py +2 -2
  34. panther/openapi/utils.py +3 -3
  35. panther/openapi/views.py +20 -37
  36. panther/pagination.py +4 -2
  37. panther/panel/apis.py +2 -7
  38. panther/panel/urls.py +2 -6
  39. panther/panel/utils.py +9 -5
  40. panther/panel/views.py +17 -23
  41. panther/permissions.py +2 -1
  42. panther/request.py +2 -1
  43. panther/response.py +53 -47
  44. panther/routings.py +12 -12
  45. panther/serializer.py +19 -20
  46. panther/test.py +73 -58
  47. panther/throttling.py +68 -3
  48. panther/utils.py +5 -11
  49. {panther-5.0.0b2.dist-info → panther-5.0.0b4.dist-info}/METADATA +1 -1
  50. panther-5.0.0b4.dist-info/RECORD +75 -0
  51. panther/monitoring.py +0 -34
  52. panther-5.0.0b2.dist-info/RECORD +0 -75
  53. {panther-5.0.0b2.dist-info → panther-5.0.0b4.dist-info}/WHEEL +0 -0
  54. {panther-5.0.0b2.dist-info → panther-5.0.0b4.dist-info}/entry_points.txt +0 -0
  55. {panther-5.0.0b2.dist-info → panther-5.0.0b4.dist-info}/licenses/LICENSE +0 -0
  56. {panther-5.0.0b2.dist-info → panther-5.0.0b4.dist-info}/top_level.txt +0 -0
panther/throttling.py CHANGED
@@ -1,11 +1,76 @@
1
1
  from collections import defaultdict
2
2
  from dataclasses import dataclass
3
- from datetime import timedelta
3
+ from datetime import datetime, timedelta
4
4
 
5
- throttling_storage = defaultdict(int)
5
+ from panther.db.connections import redis
6
+ from panther.exceptions import ThrottlingAPIError
7
+ from panther.request import Request
8
+ from panther.utils import round_datetime
9
+
10
+ # In-memory fallback storage for when Redis is unavailable
11
+ _fallback_throttle_storage = defaultdict(int)
6
12
 
7
13
 
8
14
  @dataclass(repr=False, eq=False)
9
- class Throttling:
15
+ class Throttle:
10
16
  rate: int
11
17
  duration: timedelta
18
+
19
+ @property
20
+ def time_window(self) -> datetime:
21
+ return round_datetime(datetime.now(), self.duration)
22
+
23
+ def build_cache_key(self, request: Request) -> str:
24
+ """
25
+ Generate a unique cache key based on time window, user or IP, and path.
26
+ This method is intended to be overridden by subclasses to customize throttling logic.
27
+ """
28
+ identifier = request.user.id if request.user else request.client.ip
29
+ return f'{self.time_window}-{identifier}-{request.path}'
30
+
31
+ async def get_request_count(self, request: Request) -> int:
32
+ """
33
+ Get the current request count for this key from Redis or fallback memory.
34
+ """
35
+ key = self.build_cache_key(request)
36
+
37
+ if redis.is_connected:
38
+ value = await redis.get(key)
39
+ return int(value) if value else 0
40
+
41
+ return _fallback_throttle_storage.get(key, 0)
42
+
43
+ async def increment_request_count(self, request: Request) -> None:
44
+ """
45
+ Increment the request count for this key and ensure TTL is set in Redis.
46
+ """
47
+ key = self.build_cache_key(request)
48
+
49
+ if redis.is_connected:
50
+ count = await redis.incrby(key, amount=1)
51
+ if count == 1:
52
+ ttl = int(self.duration.total_seconds())
53
+ await redis.expire(key, ttl)
54
+ else:
55
+ _fallback_throttle_storage[key] += 1
56
+
57
+ async def check_and_increment(self, request: Request) -> None:
58
+ """
59
+ Main throttling logic:
60
+ - Raises ThrottlingAPIError if limit exceeded.
61
+ - Otherwise increments the request count.
62
+ """
63
+ count = await self.get_request_count(request)
64
+ remaining = self.rate - count - 1
65
+ reset_time = self.time_window + self.duration
66
+ retry_after = int((reset_time - datetime.now()).total_seconds())
67
+
68
+ if remaining < 0:
69
+ raise ThrottlingAPIError(
70
+ headers={
71
+ 'Retry-After': str(retry_after),
72
+ 'X-RateLimit-Reset': str(int(reset_time.timestamp())),
73
+ },
74
+ )
75
+
76
+ await self.increment_request_count(request)
panther/utils.py CHANGED
@@ -33,7 +33,7 @@ def load_env(env_file: str | Path, /) -> dict[str, str]:
33
33
  raise ValueError(f'"{env_file}" is not a file.') from None
34
34
 
35
35
  with open(env_file) as file:
36
- for line in file.readlines():
36
+ for line in file:
37
37
  striped_line = line.strip()
38
38
  if not striped_line.startswith('#') and '=' in striped_line:
39
39
  key, value = striped_line.split('=', 1)
@@ -53,7 +53,7 @@ def generate_secret_key() -> str:
53
53
  return base64.urlsafe_b64encode(os.urandom(32)).decode()
54
54
 
55
55
 
56
- def round_datetime(dt: datetime, delta: timedelta):
56
+ def round_datetime(dt: datetime, delta: timedelta) -> datetime:
57
57
  """
58
58
  Example:
59
59
  >>> round_datetime(datetime(2024, 7, 15, 13, 22, 11, 562159), timedelta(days=2))
@@ -67,6 +67,7 @@ def round_datetime(dt: datetime, delta: timedelta):
67
67
 
68
68
  >>> round_datetime(datetime(2024, 7, 18, 13, 22, 11, 562159), timedelta(days=2))
69
69
  datetime.datetime(2024, 7, 18, 0, 0)
70
+
70
71
  """
71
72
  return datetime.min + round((dt - datetime.min) / delta) * delta
72
73
 
@@ -87,19 +88,12 @@ def scrypt(password: str, salt: bytes, digest: bool = False) -> str | bytes:
87
88
  h_len: The length in octets of the hash function (32 for SHA256).
88
89
  mf_len: The length in octets of the output of the mixing function (SMix below). Defined as r * 128 in RFC7914.
89
90
  """
90
- n = 2 ** 14 # 16384
91
+ n = 2**14 # 16384
91
92
  r = 8
92
93
  p = 10
93
94
  dk_len = 64
94
95
 
95
- derived_key = hashlib.scrypt(
96
- password=password.encode(),
97
- salt=salt,
98
- n=n,
99
- r=r,
100
- p=p,
101
- dklen=dk_len
102
- )
96
+ derived_key = hashlib.scrypt(password=password.encode(), salt=salt, n=n, r=r, p=p, dklen=dk_len)
103
97
  if digest:
104
98
  return hashlib.md5(derived_key).hexdigest()
105
99
  return derived_key
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panther
3
- Version: 5.0.0b2
3
+ Version: 5.0.0b4
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
@@ -0,0 +1,75 @@
1
+ panther/__init__.py,sha256=X4CUQB2xphMKSsHepAZPm5n5K0uNc-zhZt9i3Hs_jN8,115
2
+ panther/_load_configs.py,sha256=9SMiJm4N5wOZYYpM5BfchvHuTg7PZOmvfIkiloUQLDk,11283
3
+ panther/_utils.py,sha256=5UN0DBNTEqHejK6EOnG9IYyH1gK9OvGXYlNp5G0iFuU,4720
4
+ panther/app.py,sha256=1WsVwzWZBxA5lO6v18Renq9oYqySY0gRFFT42cPkbFY,11409
5
+ panther/authentications.py,sha256=JdCeXKvo6iHmxeXsZEmFvXQsLkI149g1dIR_md6blV8,7844
6
+ panther/background_tasks.py,sha256=A__lY4IijGbRD9GKtbUK_c8cChtFW0jPaxoQHJ25bsk,7539
7
+ panther/base_request.py,sha256=MkzTv_Si4scJFZgHRaZurwjN6KthrKf1aqIN8u811z0,4950
8
+ panther/base_websocket.py,sha256=tCazsv5ILt-8wqYfsRB0NwXUIb-_wdeSTEBt3xjbneg,11000
9
+ panther/caching.py,sha256=nNyY6rZ9fnvsH44pk4eNaLuBYBDKw5CV6HC-7FAn6zM,2288
10
+ panther/configs.py,sha256=Hg-4B9mD4QL5aALEd7NJ8bTMikJWS1dhVtKe0n42Buc,3834
11
+ panther/events.py,sha256=-AFsJwZe9RpQ9xQQArUfqCPjv4ZRaFZ0shzTuO5WmWc,1576
12
+ panther/exceptions.py,sha256=QubEyGPnKlo4e7dR_SU2JbRB20vZ42LcUH3JvmOK5Xg,2231
13
+ panther/file_handler.py,sha256=6zXe36eaCyqtZFX2bMT9xl8tjimoHMcD7csLoPx_8EA,1323
14
+ panther/generics.py,sha256=v66yp6-jNdXh7EW5U-1g_f0zrp8_KaGr6OcbXsYbuzM,7318
15
+ panther/logging.py,sha256=g-RUuyCveqdMrEQXWIjIPZi2jYCJmOmZV8TvD_uMrEU,2075
16
+ panther/main.py,sha256=0i5HoJ4IGY2bF25lK1V6x7_f-boxceVz6zLj6Q6vTi8,7557
17
+ panther/pagination.py,sha256=bQEpf-FMil6zOwGuGD6VEowht2_13sT5jl-Cflwo_-E,1644
18
+ panther/permissions.py,sha256=UdPHVZYLWIYaf94OauE1QdVlj66_iE8B3rb336MBBcU,400
19
+ panther/request.py,sha256=IVuDdLdceCzo2vmICnWwoD2ag1eNc09C5XHZnULQxUw,1888
20
+ panther/response.py,sha256=k8ZQ6BIKuLc3vRRfSunm7twGixD6145ByWloSAqOrQQ,10495
21
+ panther/routings.py,sha256=QwE7EyQD1wdgXS8JK80tV36tIrrBR7fRZ1OkhpA8m7s,6482
22
+ panther/serializer.py,sha256=SrVROW9HyZS2QZDwlcrs_5npByIk-4bijm6_vAj2M24,9064
23
+ panther/status.py,sha256=Gc_PnYrHfInTsZpGbqiCfDB-py1C7Rh8KMdb6Lq9Exs,3346
24
+ panther/test.py,sha256=EReFLKhDtOoGQVTPSdtI31xi-u4SfwirA179G9_rIAE,7374
25
+ panther/throttling.py,sha256=EnU9PtulAwNTxsheun-s-kjJ1YL3jgj0bpxe8jGowlQ,2630
26
+ panther/utils.py,sha256=H2DrUz62ULv9BA6XdSJbaArRZG1ZQoJZmaFMXBvq_4c,4252
27
+ panther/websocket.py,sha256=er44pGU3Zm-glj4imS5l1Qdk7WNc_3Jpq7SPkeApPlM,1532
28
+ panther/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ panther/cli/create_command.py,sha256=iIAzS8C8rFKQ1idVSR5SMYRHWcwK09EYEqIqcBiiVXQ,10336
30
+ panther/cli/main.py,sha256=xWFxu_9cbrzsxgrkj0SrT2QUny3GMgJJuuAzK2OnR_M,1518
31
+ panther/cli/monitor_command.py,sha256=1hhPZNXGzvl-XXM0wwJol4dUwVgX3d00r3oV1mvNcS0,4462
32
+ panther/cli/run_command.py,sha256=ZInQQGV-QaLS7XUEUPqP_3iR2Nrto9unaOvYAs3mF9M,356
33
+ panther/cli/template.py,sha256=C3jb6m_NQRzur-_DNtEKiptMYtxTvd5MNM1qIgpFMNA,5331
34
+ panther/cli/utils.py,sha256=SjqggWpgGVH_JiMNQFnXPWzoMYxIHI2p9WO3-c59wU4,5542
35
+ panther/db/__init__.py,sha256=w9lEL0vRqb18Qx_iUJipUR_fi5GQ5uVX0DWycx14x08,50
36
+ panther/db/connections.py,sha256=AJpl7qgPuUTqDvuGW6VkLPRhNwrgTVoIDak3i7uI4GY,3982
37
+ panther/db/cursor.py,sha256=glFyfVriOmluajlq77u7cKF2Gnmo6iF5qLqT63yeigg,1783
38
+ panther/db/models.py,sha256=6WvWb9NkxZz7Srw0YCdZeIDNZt68nSEkuOoazh-Efm0,3250
39
+ panther/db/utils.py,sha256=GiRQ4t9csEFKmGViej7dyfZaaiWMdTAQeWzdoCWTJac,1574
40
+ panther/db/queries/__init__.py,sha256=uF4gvBjLBJ-Yl3WLqoZEVNtHCVhFRKW3_Vi44pJxDNI,45
41
+ panther/db/queries/base_queries.py,sha256=GFPEvSV7SGAVpJFHiIkhfKBf0xkLsyXvmW7bRI88HOU,3738
42
+ panther/db/queries/mongodb_queries.py,sha256=FTWcJc5vDy163Pn-_vyeeRlljs8SOKlARQ_gi3AvBtc,13389
43
+ panther/db/queries/pantherdb_queries.py,sha256=GlRRFvbaeVR3x2dYqlQIvsWxAWUcPflZ2u6kuJYvSIM,4620
44
+ panther/db/queries/queries.py,sha256=nhjrFk02O-rLUZ5slS3jHZ9wnxPrFLmiAZLaeVePKiA,12408
45
+ panther/middlewares/__init__.py,sha256=8VXd-K3L0a5ZkGb-NUipn3K8wxWAVIiOM7fQrcm_dTM,87
46
+ panther/middlewares/base.py,sha256=V5PuuemMCrQslIBK-sER4YZGdSDMzRFhZHjRUiIkhbY,721
47
+ panther/middlewares/cors.py,sha256=g4ougecREr88wnBSHziCeIVyIUnP0rYEs4-Izbf8tBI,3032
48
+ panther/middlewares/monitoring.py,sha256=ebkk84be6cGnUxi0IETnzKoYsGC2O_4kAarZ1cRynnA,1487
49
+ panther/openapi/__init__.py,sha256=UAkcGDxOltOkZwx3vZjigwfHUdb4xnidC6e_Viezfv4,47
50
+ panther/openapi/urls.py,sha256=HrYkS2sPgiTB6JpRCZaAwOSrw9lWa8EsfGJXZsp0B_0,78
51
+ panther/openapi/utils.py,sha256=_wAhTbcXvtXTMGjOUGcKm9sjDfoNhUFFsxHdrlEmguI,6492
52
+ panther/openapi/views.py,sha256=sUhjY9odz2kT_Xzl7MAyC4ARDsvPLHrH8lzNTo_Zf5U,3405
53
+ panther/openapi/templates/openapi.html,sha256=VAaJytOBFuR1rvGXOxbXOoJlurbeAl-VuTZu7Hk6LLs,889
54
+ panther/panel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ panther/panel/apis.py,sha256=0OWwiySdSinjYFVs6r97nVaSDO51DZ9f2VlEWAM87-E,2364
56
+ panther/panel/middlewares.py,sha256=xOYpIsy-fqc8OuieePLviUxmR6Tsu-kg3UtgerUKyHo,379
57
+ panther/panel/urls.py,sha256=10BEdB81sNSOxWKFdcAwA2AGV1ddgen4ntXcSk2nx6U,253
58
+ panther/panel/utils.py,sha256=hwHtRYiea8FNjLGhEAAyX7-1LlCSUV-4pHslG79PLCY,4258
59
+ panther/panel/views.py,sha256=go7qQwRliKOiYcQ2uJUluTRNqUh9q7KmuXc4y1eH8Q8,5040
60
+ panther/panel/templates/base.html,sha256=kHDzfmlIf14eLrZHymIHdywr36W7cJXKtqFpVhw-x34,327
61
+ panther/panel/templates/create.html,sha256=2cKjWpNElv390PPYzoI7MGqVjgy9692x3vpxwAJE7GE,581
62
+ panther/panel/templates/create.js,sha256=zO_GfaHnjVI25zx4wGhUPA7aEkCukKMpabJfuiOib7c,40180
63
+ panther/panel/templates/detail.html,sha256=wFuePktVNchECgPhMxlXjX_KH3tqQvVsTTUmtOWsqjA,1490
64
+ panther/panel/templates/home.html,sha256=vSVHoCWeqY4AhQiC-UVAvu10m2bINneO6_PLyOS9R4Q,238
65
+ panther/panel/templates/home.js,sha256=bC8io0iKdAftSvrapkwx7ZPAbVq3UzapV9sv5uWa8FY,849
66
+ panther/panel/templates/login.html,sha256=W6V1rgHAno7yTbP6Il38ZvJp4LdlJ8BjM4UuyPkjaTA,1625
67
+ panther/panel/templates/sidebar.html,sha256=XikovZsJrth0nvKogvZoh3Eb2Bq7xdeGTlsdlyud450,618
68
+ panther/panel/templates/table.html,sha256=fWdaIHEHAuwuPaAfOtXkD-3yvSocyDmtys00_D2yRh8,2176
69
+ panther/panel/templates/table.js,sha256=MTdf77571Gtmg4l8HkY-5fM-utIL3lc0O8hv6vLBCYk,10414
70
+ panther-5.0.0b4.dist-info/licenses/LICENSE,sha256=2aF1hL2aC0zRPjzUkSxJUzZbn2_uLoOkn7DHjzZni-I,1524
71
+ panther-5.0.0b4.dist-info/METADATA,sha256=2NiQy6W9FrVHUevwkWiTVcoJGUy7Z5dT_iKPKjZN7bI,7026
72
+ panther-5.0.0b4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
73
+ panther-5.0.0b4.dist-info/entry_points.txt,sha256=6GPxYFGuzVfNB4YpHFJvYex6iWah5_tLnirAHwj2Qsg,51
74
+ panther-5.0.0b4.dist-info/top_level.txt,sha256=VbBs02JGXTIoHMzsX-eLOk2MCbBZzQbLhWiYpI7xI2g,8
75
+ panther-5.0.0b4.dist-info/RECORD,,
panther/monitoring.py DELETED
@@ -1,34 +0,0 @@
1
- import logging
2
- from time import perf_counter
3
- from typing import Literal
4
-
5
- from panther.base_request import BaseRequest
6
- from panther.configs import config
7
-
8
- logger = logging.getLogger('monitoring')
9
-
10
-
11
- class Monitoring:
12
- """
13
- Create Log Message Like Below:
14
- date_time | method | path | ip:port | response_time(seconds) | status
15
- """
16
- def __init__(self, is_ws: bool = False):
17
- self.is_ws = is_ws
18
-
19
- async def before(self, request: BaseRequest):
20
- if config.MONITORING:
21
- ip, port = request.client
22
-
23
- if self.is_ws:
24
- method = 'WS'
25
- else:
26
- method = request.scope['method']
27
-
28
- self.log = f'{method} | {request.path} | {ip}:{port}'
29
- self.start_time = perf_counter()
30
-
31
- async def after(self, status: int | Literal['Accepted', 'Rejected', 'Closed'], /):
32
- if config.MONITORING:
33
- response_time = perf_counter() - self.start_time # Seconds
34
- logger.info(f'{self.log} | {response_time} | {status}')
@@ -1,75 +0,0 @@
1
- panther/__init__.py,sha256=EN8vI-Orve2wCHyNc_rtgpC7s2UUCP2lWlN3nc3w3Oc,115
2
- panther/_load_configs.py,sha256=1mMZeULMIgCxuPIXjNCdMPpqpjBm_rf4IgiD7Zk5MWs,10964
3
- panther/_utils.py,sha256=nJK4QdTB9SmcVoRKy3hRvcdvceVGlBQ-MQG38j1BLc8,4130
4
- panther/app.py,sha256=x8UsN3Ct2LfnvyXHkX_yIimBV73W19sL5xxF3RSRaMw,11074
5
- panther/authentications.py,sha256=LK-4fESiGnot2kwxg5qm5RXTOOcqOnMTQ-HL4UBtc0g,6259
6
- panther/background_tasks.py,sha256=HBYubDIiO_673cl_5fqCUP9zzimzRgRkDSkag9Msnbs,7656
7
- panther/base_request.py,sha256=j87aeRFlR8Ix8Nrl0vehuL9QTkKtx7IVG8euUwGXh6U,4606
8
- panther/base_websocket.py,sha256=tqdbDwCJmyonUNAp5-XeIcjxZjALfDwviAbYKU6mY24,11003
9
- panther/caching.py,sha256=0UWg2xlTkyTKcf6rMjf-oZIE_kJWpPfpKKaDOCZxazg,4299
10
- panther/configs.py,sha256=Ge2GlMxkG9UY5ySp_7hvXy_kV6_ipHv1uKoL_L3Tntc,3408
11
- panther/events.py,sha256=tJvqkUA_Zs-tO_6ZpBmP_KkreFeM70fX8A7V6bCJUsU,1360
12
- panther/exceptions.py,sha256=UEwpIIG57zNEm2CouU5Bi_mSUWYNEXi2FKqhjhMc4js,2288
13
- panther/file_handler.py,sha256=I94tpbtTVniBnnUMkFr3Eis6kPDt8sLzS5u8TzFrR5I,1323
14
- panther/generics.py,sha256=NVq43L8rz1jtMYD66O3p0DR295fiiongjq8bPIqBLeE,7261
15
- panther/logging.py,sha256=SGgF9faQM1QmbmMPVc6m1DY-TbV329kTD8BuzGLx3I0,2073
16
- panther/main.py,sha256=aEDGWjOe2rABEYyEkPGKLt4m45lJM6hEOGKYCiEHxk8,7599
17
- panther/monitoring.py,sha256=C0tYBKGci6QR33CN-MixMzCP24ka0a6V0AU2H1sS4HU,1026
18
- panther/pagination.py,sha256=VvvNsMObIarjUx9F8T91TX-9A2Ymy18Ms_hB60lZdEA,1641
19
- panther/permissions.py,sha256=9-J5vzvEKa_PITwEVQbZZv8PG2FOu05YBlD5yMrKcfc,348
20
- panther/request.py,sha256=Ho2tKvwZSKA4_sklZQNE9hjFuVrbt0O5R6sZ1HtCfI0,1861
21
- panther/response.py,sha256=Wq90Tt6Bt0NLi6QDXwkdovqR2cvz2_SqmGTRIKFDbos,9958
22
- panther/routings.py,sha256=Hcug2JZXwqR44PDSgkvG9v2dUgSNDJEIbm8E7t4Q72U,6414
23
- panther/serializer.py,sha256=R5U9H75QRbyCq_CI_i9STlnAKit-DDEPH6-AZ2RyDmA,9085
24
- panther/status.py,sha256=Gc_PnYrHfInTsZpGbqiCfDB-py1C7Rh8KMdb6Lq9Exs,3346
25
- panther/test.py,sha256=RsQtP5IURLWR__BihOjruWoX3NscmGDqDqj1CfAb3bI,7037
26
- panther/throttling.py,sha256=mVa_mGv6w_Ad7LLtV4eG5QpDwwNsk4QjFFi0mIHQBnE,231
27
- panther/utils.py,sha256=92t9NFjzdswN133utDc2ovPgOZzqy_nF4bbrb5DDuY0,4307
28
- panther/websocket.py,sha256=er44pGU3Zm-glj4imS5l1Qdk7WNc_3Jpq7SPkeApPlM,1532
29
- panther/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- panther/cli/create_command.py,sha256=3_2xGWzJjdhCCgQHYvn7ikCl12wqTw6jT_Pu2EvfZWc,10344
31
- panther/cli/main.py,sha256=XvkKMJsi-wvWO7GJsDQng7RShK8UnnKICu3c1H9OFNY,1517
32
- panther/cli/monitor_command.py,sha256=ga8-6shrq0cz3Lo6ueSPZuetkLFdypesVO6fVQE01KM,4219
33
- panther/cli/run_command.py,sha256=yWcDoWC-c4ph4M5EDj0jvR9xSjh-apG5r6-NpDdArUo,2195
34
- panther/cli/template.py,sha256=ZIU4hLy9aNGCtUMt0LS8zoUf6daYQrLDteN-iLkIWTI,5349
35
- panther/cli/utils.py,sha256=84W0bS-FPoJf3BsgOei2OBeoflcxXwy99Gft0ujF1Ss,5355
36
- panther/db/__init__.py,sha256=w9lEL0vRqb18Qx_iUJipUR_fi5GQ5uVX0DWycx14x08,50
37
- panther/db/connections.py,sha256=8QHQ_tmni4gfLHQCR7jmBFfvFgJCOrTQXdQiDRJRuv0,4205
38
- panther/db/cursor.py,sha256=EvjVyOIkg_uynX5vCpVFpAzAw0Yb_R0II8mKgqBN_7c,1784
39
- panther/db/models.py,sha256=gmqWjqbDE6DggTmUnqAipi9l0JfmDgiXttr9qCKK208,2793
40
- panther/db/utils.py,sha256=ZZa3TMkuRtssl5ZRItFLonyxvMFsTq4fmTD4BblhLDA,1589
41
- panther/db/queries/__init__.py,sha256=uF4gvBjLBJ-Yl3WLqoZEVNtHCVhFRKW3_Vi44pJxDNI,45
42
- panther/db/queries/base_queries.py,sha256=GG3F9qFrIl6ibzvbjfDonztJvkUbjzPYHo8PNcdcj-0,3775
43
- panther/db/queries/mongodb_queries.py,sha256=QCP1ibnd-x8js8XIC4nhgdfiJAj1606CkpSQ_-j2y8Y,13394
44
- panther/db/queries/pantherdb_queries.py,sha256=h6LNsEk7srJw-dpqTl46ZSAO5BLFGVymQ4JnU75B4zM,4611
45
- panther/db/queries/queries.py,sha256=sTa0m9q8tf2ugbFDmj4GRfRQOyNFmSBFfDqIVcRjKIM,12433
46
- panther/middlewares/__init__.py,sha256=8VXd-K3L0a5ZkGb-NUipn3K8wxWAVIiOM7fQrcm_dTM,87
47
- panther/middlewares/base.py,sha256=V5PuuemMCrQslIBK-sER4YZGdSDMzRFhZHjRUiIkhbY,721
48
- panther/middlewares/monitoring.py,sha256=pxbRiM20grCNyAJZwouAOe3gLbdveSObStJF5WdCFyA,1486
49
- panther/openapi/__init__.py,sha256=UAkcGDxOltOkZwx3vZjigwfHUdb4xnidC6e_Viezfv4,47
50
- panther/openapi/urls.py,sha256=99f7hx_z65Vw6p9Kg-Vz5hU9_FlIhJeVnA1-CPm1TTI,70
51
- panther/openapi/utils.py,sha256=YxBA9HUShgoH0MphW27xL_qS0uIA0gQsh705hxnJlYE,6504
52
- panther/openapi/views.py,sha256=5B1BifNeUojLVs3ygk7KOEjUSnsMllslSdFgsPgd8yA,3908
53
- panther/openapi/templates/openapi.html,sha256=VAaJytOBFuR1rvGXOxbXOoJlurbeAl-VuTZu7Hk6LLs,889
54
- panther/panel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- panther/panel/apis.py,sha256=COsbwKZyTgyHvHYbpDfusifAH9ojMS3z1KhZCt9M-Ms,2428
56
- panther/panel/middlewares.py,sha256=xOYpIsy-fqc8OuieePLviUxmR6Tsu-kg3UtgerUKyHo,379
57
- panther/panel/urls.py,sha256=xLEy1qA4MWOLApkecyz1FxDefNthOUCqYft5XsctKys,387
58
- panther/panel/utils.py,sha256=UFDPmST-c5T-pa5bg4wBIzZMgQIgAqervL4ojOeofq8,4219
59
- panther/panel/views.py,sha256=VnmKwkiuBgbIIFsqAqcqfOn8S5N837Y1TUH_2U6PkXs,5148
60
- panther/panel/templates/base.html,sha256=kHDzfmlIf14eLrZHymIHdywr36W7cJXKtqFpVhw-x34,327
61
- panther/panel/templates/create.html,sha256=2cKjWpNElv390PPYzoI7MGqVjgy9692x3vpxwAJE7GE,581
62
- panther/panel/templates/create.js,sha256=zO_GfaHnjVI25zx4wGhUPA7aEkCukKMpabJfuiOib7c,40180
63
- panther/panel/templates/detail.html,sha256=wFuePktVNchECgPhMxlXjX_KH3tqQvVsTTUmtOWsqjA,1490
64
- panther/panel/templates/home.html,sha256=vSVHoCWeqY4AhQiC-UVAvu10m2bINneO6_PLyOS9R4Q,238
65
- panther/panel/templates/home.js,sha256=bC8io0iKdAftSvrapkwx7ZPAbVq3UzapV9sv5uWa8FY,849
66
- panther/panel/templates/login.html,sha256=W6V1rgHAno7yTbP6Il38ZvJp4LdlJ8BjM4UuyPkjaTA,1625
67
- panther/panel/templates/sidebar.html,sha256=XikovZsJrth0nvKogvZoh3Eb2Bq7xdeGTlsdlyud450,618
68
- panther/panel/templates/table.html,sha256=fWdaIHEHAuwuPaAfOtXkD-3yvSocyDmtys00_D2yRh8,2176
69
- panther/panel/templates/table.js,sha256=MTdf77571Gtmg4l8HkY-5fM-utIL3lc0O8hv6vLBCYk,10414
70
- panther-5.0.0b2.dist-info/licenses/LICENSE,sha256=2aF1hL2aC0zRPjzUkSxJUzZbn2_uLoOkn7DHjzZni-I,1524
71
- panther-5.0.0b2.dist-info/METADATA,sha256=2vCEzF7CRa35QMey3KB_c1tV5edvWU3oOwq2sa6b3hw,7026
72
- panther-5.0.0b2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
73
- panther-5.0.0b2.dist-info/entry_points.txt,sha256=6GPxYFGuzVfNB4YpHFJvYex6iWah5_tLnirAHwj2Qsg,51
74
- panther-5.0.0b2.dist-info/top_level.txt,sha256=VbBs02JGXTIoHMzsX-eLOk2MCbBZzQbLhWiYpI7xI2g,8
75
- panther-5.0.0b2.dist-info/RECORD,,