panther 4.3.7__py3-none-any.whl → 5.0.0b2__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 (59) hide show
  1. panther/__init__.py +1 -1
  2. panther/_load_configs.py +78 -64
  3. panther/_utils.py +1 -1
  4. panther/app.py +126 -60
  5. panther/authentications.py +26 -9
  6. panther/base_request.py +27 -2
  7. panther/base_websocket.py +26 -27
  8. panther/cli/create_command.py +1 -0
  9. panther/cli/main.py +19 -27
  10. panther/cli/monitor_command.py +8 -4
  11. panther/cli/template.py +11 -6
  12. panther/cli/utils.py +3 -2
  13. panther/configs.py +7 -9
  14. panther/db/cursor.py +23 -7
  15. panther/db/models.py +26 -19
  16. panther/db/queries/base_queries.py +1 -1
  17. panther/db/queries/mongodb_queries.py +177 -13
  18. panther/db/queries/pantherdb_queries.py +5 -5
  19. panther/db/queries/queries.py +1 -1
  20. panther/events.py +10 -4
  21. panther/exceptions.py +24 -2
  22. panther/generics.py +2 -2
  23. panther/main.py +90 -117
  24. panther/middlewares/__init__.py +1 -1
  25. panther/middlewares/base.py +15 -19
  26. panther/middlewares/monitoring.py +42 -0
  27. panther/openapi/__init__.py +1 -0
  28. panther/openapi/templates/openapi.html +27 -0
  29. panther/openapi/urls.py +5 -0
  30. panther/openapi/utils.py +167 -0
  31. panther/openapi/views.py +101 -0
  32. panther/pagination.py +1 -1
  33. panther/panel/middlewares.py +10 -0
  34. panther/panel/templates/base.html +14 -0
  35. panther/panel/templates/create.html +21 -0
  36. panther/panel/templates/create.js +1270 -0
  37. panther/panel/templates/detail.html +55 -0
  38. panther/panel/templates/home.html +9 -0
  39. panther/panel/templates/home.js +30 -0
  40. panther/panel/templates/login.html +47 -0
  41. panther/panel/templates/sidebar.html +13 -0
  42. panther/panel/templates/table.html +73 -0
  43. panther/panel/templates/table.js +339 -0
  44. panther/panel/urls.py +10 -5
  45. panther/panel/utils.py +98 -0
  46. panther/panel/views.py +143 -0
  47. panther/request.py +3 -0
  48. panther/response.py +91 -53
  49. panther/routings.py +7 -2
  50. panther/serializer.py +1 -1
  51. panther/utils.py +34 -26
  52. panther/websocket.py +3 -0
  53. {panther-4.3.7.dist-info → panther-5.0.0b2.dist-info}/METADATA +19 -17
  54. panther-5.0.0b2.dist-info/RECORD +75 -0
  55. {panther-4.3.7.dist-info → panther-5.0.0b2.dist-info}/WHEEL +1 -1
  56. panther-4.3.7.dist-info/RECORD +0 -57
  57. {panther-4.3.7.dist-info → panther-5.0.0b2.dist-info}/entry_points.txt +0 -0
  58. {panther-4.3.7.dist-info → panther-5.0.0b2.dist-info}/licenses/LICENSE +0 -0
  59. {panther-4.3.7.dist-info → panther-5.0.0b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,101 @@
1
+ import types
2
+
3
+ from panther.app import GenericAPI
4
+ from panther.configs import config
5
+ from panther.openapi.utils import ParseEndpoint
6
+ from panther.response import TemplateResponse
7
+
8
+
9
+ class OpenAPI(GenericAPI):
10
+ @classmethod
11
+ def get_content(cls, endpoint, method):
12
+ parsed = ParseEndpoint(endpoint=endpoint, method=method)
13
+
14
+ if endpoint.output_schema:
15
+ status_code = endpoint.output_schema.status_code
16
+ schema = endpoint.output_schema.model.schema()
17
+ else:
18
+ status_code = parsed.status_code
19
+ schema = {
20
+ 'properties': {
21
+ k: {'default': v} for k, v in parsed.data.items()
22
+ }
23
+ }
24
+
25
+ responses = {}
26
+ if schema:
27
+ responses = {
28
+ 'responses': {
29
+ status_code: {
30
+ 'content': {
31
+ 'application/json': {
32
+ 'schema': schema
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+ request_body = {}
39
+ if endpoint.input_model and method in ['post', 'put', 'patch']:
40
+ request_body = {
41
+ 'requestBody': {
42
+ 'required': True,
43
+ 'content': {
44
+ 'application/json': {
45
+ 'schema': endpoint.input_model.schema() if endpoint.input_model else {}
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ content = {
52
+ 'title': parsed.title,
53
+ 'summary': endpoint.__doc__,
54
+ 'tags': ['.'.join(endpoint.__module__.rsplit('.')[:-1]) or endpoint.__module__],
55
+ } | responses | request_body
56
+ return {method: content}
57
+
58
+ def get(self):
59
+ paths = {}
60
+ # TODO:
61
+ # Try to process the endpoint with `ast` if output_schema is None
62
+ # Create Component for output_schema.model and input_model
63
+ #
64
+ for url, endpoint in config.FLAT_URLS.items():
65
+ if url == '':
66
+ url = '/'
67
+ if not url.startswith('/'):
68
+ url = f'/{url}'
69
+ paths[url] = {}
70
+
71
+ if isinstance(endpoint, types.FunctionType):
72
+ methods = endpoint.methods
73
+ if methods is None or 'POST' in methods:
74
+ paths[url] |= self.get_content(endpoint, 'post')
75
+ if methods is None or 'GET' in methods:
76
+ paths[url] |= self.get_content(endpoint, 'get')
77
+ if methods is None or 'PUT' in methods:
78
+ paths[url] |= self.get_content(endpoint, 'put')
79
+ if methods is None or 'PATCH' in methods:
80
+ paths[url] |= self.get_content(endpoint, 'patch')
81
+ if methods is None or 'DELETE' in methods:
82
+ paths[url] |= self.get_content(endpoint, 'delete')
83
+ else:
84
+ if endpoint.post is not GenericAPI.post:
85
+ paths[url] |= self.get_content(endpoint, 'post')
86
+ if endpoint.get is not GenericAPI.get:
87
+ paths[url] |= self.get_content(endpoint, 'get')
88
+ if endpoint.put is not GenericAPI.put:
89
+ paths[url] |= self.get_content(endpoint, 'put')
90
+ if endpoint.patch is not GenericAPI.patch:
91
+ paths[url] |= self.get_content(endpoint, 'patch')
92
+ if endpoint.delete is not GenericAPI.delete:
93
+ paths[url] |= self.get_content(endpoint, 'delete')
94
+
95
+ openapi_content = {
96
+ 'openapi': '3.0.0',
97
+ 'paths': paths,
98
+ 'components': {}
99
+ }
100
+ print(f'{openapi_content=}')
101
+ return TemplateResponse(name='openapi.html', context={'openapi_content': openapi_content})
panther/pagination.py CHANGED
@@ -11,7 +11,7 @@ class Pagination:
11
11
  'count': 10,
12
12
  'next': '?limit=10&skip=10',
13
13
  'previous': None,
14
- results: [...]
14
+ 'results': [...]
15
15
  }
16
16
  """
17
17
  DEFAULT_LIMIT = 20
@@ -0,0 +1,10 @@
1
+ from panther.middlewares import HTTPMiddleware
2
+ from panther.request import Request
3
+ from panther.response import RedirectResponse
4
+
5
+
6
+ class RedirectToSlashMiddleware(HTTPMiddleware):
7
+ async def __call__(self, request: Request):
8
+ if not request.path.endswith('/'):
9
+ return RedirectResponse(request.path + '/')
10
+ return await self.dispatch(request=request)
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>{{ title }}</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ </head>
10
+ <body class="bg-gray-900 text-white p-8">
11
+ {% block content %}
12
+ {% endblock %}
13
+ </body>
14
+ </html>
@@ -0,0 +1,21 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block content %}
4
+ <div class="max-w-4xl mx-auto">
5
+ <h1 class="text-2xl font-semibold mb-6">Create New Record</h1>
6
+
7
+ <form id="createForm" class="space-y-4 bg-gray-800 p-6 rounded-lg">
8
+ <div id="dynamicInputs" class="space-y-4">
9
+ <!-- Dynamic inputs will be generated here -->
10
+ </div>
11
+ <button type="submit" class="w-full bg-blue-600 hover:bg-blue-500 text-white py-2 px-4 rounded-lg">
12
+ Submit
13
+ </button>
14
+ </form>
15
+ </div>
16
+ <script>
17
+ const isUpdate = false;
18
+ const data = {};
19
+ {% include "create.js" %}
20
+ </script>
21
+ {% endblock %}