panther 4.1.3__tar.gz → 4.2.0__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.
Files changed (81) hide show
  1. {panther-4.1.3 → panther-4.2.0}/PKG-INFO +1 -1
  2. {panther-4.1.3 → panther-4.2.0}/panther/__init__.py +1 -1
  3. {panther-4.1.3 → panther-4.2.0}/panther/app.py +14 -0
  4. {panther-4.1.3 → panther-4.2.0}/panther/base_request.py +2 -5
  5. {panther-4.1.3 → panther-4.2.0}/panther/cli/create_command.py +1 -1
  6. {panther-4.1.3 → panther-4.2.0}/panther/cli/template.py +1 -0
  7. {panther-4.1.3 → panther-4.2.0}/panther/db/queries/mongodb_queries.py +1 -1
  8. {panther-4.1.3 → panther-4.2.0}/panther/db/utils.py +2 -2
  9. {panther-4.1.3 → panther-4.2.0}/panther.egg-info/PKG-INFO +1 -1
  10. {panther-4.1.3 → panther-4.2.0}/tests/test_database.py +18 -0
  11. {panther-4.1.3 → panther-4.2.0}/LICENSE +0 -0
  12. {panther-4.1.3 → panther-4.2.0}/README.md +0 -0
  13. {panther-4.1.3 → panther-4.2.0}/panther/_load_configs.py +0 -0
  14. {panther-4.1.3 → panther-4.2.0}/panther/_utils.py +0 -0
  15. {panther-4.1.3 → panther-4.2.0}/panther/authentications.py +0 -0
  16. {panther-4.1.3 → panther-4.2.0}/panther/background_tasks.py +0 -0
  17. {panther-4.1.3 → panther-4.2.0}/panther/base_websocket.py +0 -0
  18. {panther-4.1.3 → panther-4.2.0}/panther/caching.py +0 -0
  19. {panther-4.1.3 → panther-4.2.0}/panther/cli/__init__.py +0 -0
  20. {panther-4.1.3 → panther-4.2.0}/panther/cli/main.py +0 -0
  21. {panther-4.1.3 → panther-4.2.0}/panther/cli/monitor_command.py +0 -0
  22. {panther-4.1.3 → panther-4.2.0}/panther/cli/run_command.py +0 -0
  23. {panther-4.1.3 → panther-4.2.0}/panther/cli/utils.py +0 -0
  24. {panther-4.1.3 → panther-4.2.0}/panther/configs.py +0 -0
  25. {panther-4.1.3 → panther-4.2.0}/panther/db/__init__.py +0 -0
  26. {panther-4.1.3 → panther-4.2.0}/panther/db/connections.py +0 -0
  27. {panther-4.1.3 → panther-4.2.0}/panther/db/cursor.py +0 -0
  28. {panther-4.1.3 → panther-4.2.0}/panther/db/models.py +0 -0
  29. {panther-4.1.3 → panther-4.2.0}/panther/db/queries/__init__.py +0 -0
  30. {panther-4.1.3 → panther-4.2.0}/panther/db/queries/base_queries.py +0 -0
  31. {panther-4.1.3 → panther-4.2.0}/panther/db/queries/pantherdb_queries.py +0 -0
  32. {panther-4.1.3 → panther-4.2.0}/panther/db/queries/queries.py +0 -0
  33. {panther-4.1.3 → panther-4.2.0}/panther/events.py +0 -0
  34. {panther-4.1.3 → panther-4.2.0}/panther/exceptions.py +0 -0
  35. {panther-4.1.3 → panther-4.2.0}/panther/file_handler.py +0 -0
  36. {panther-4.1.3 → panther-4.2.0}/panther/generics.py +0 -0
  37. {panther-4.1.3 → panther-4.2.0}/panther/logging.py +0 -0
  38. {panther-4.1.3 → panther-4.2.0}/panther/main.py +0 -0
  39. {panther-4.1.3 → panther-4.2.0}/panther/middlewares/__init__.py +0 -0
  40. {panther-4.1.3 → panther-4.2.0}/panther/middlewares/base.py +0 -0
  41. {panther-4.1.3 → panther-4.2.0}/panther/monitoring.py +0 -0
  42. {panther-4.1.3 → panther-4.2.0}/panther/pagination.py +0 -0
  43. {panther-4.1.3 → panther-4.2.0}/panther/panel/__init__.py +0 -0
  44. {panther-4.1.3 → panther-4.2.0}/panther/panel/apis.py +0 -0
  45. {panther-4.1.3 → panther-4.2.0}/panther/panel/urls.py +0 -0
  46. {panther-4.1.3 → panther-4.2.0}/panther/panel/utils.py +0 -0
  47. {panther-4.1.3 → panther-4.2.0}/panther/permissions.py +0 -0
  48. {panther-4.1.3 → panther-4.2.0}/panther/request.py +0 -0
  49. {panther-4.1.3 → panther-4.2.0}/panther/response.py +0 -0
  50. {panther-4.1.3 → panther-4.2.0}/panther/routings.py +0 -0
  51. {panther-4.1.3 → panther-4.2.0}/panther/serializer.py +0 -0
  52. {panther-4.1.3 → panther-4.2.0}/panther/status.py +0 -0
  53. {panther-4.1.3 → panther-4.2.0}/panther/test.py +0 -0
  54. {panther-4.1.3 → panther-4.2.0}/panther/throttling.py +0 -0
  55. {panther-4.1.3 → panther-4.2.0}/panther/utils.py +0 -0
  56. {panther-4.1.3 → panther-4.2.0}/panther/websocket.py +0 -0
  57. {panther-4.1.3 → panther-4.2.0}/panther.egg-info/SOURCES.txt +0 -0
  58. {panther-4.1.3 → panther-4.2.0}/panther.egg-info/dependency_links.txt +0 -0
  59. {panther-4.1.3 → panther-4.2.0}/panther.egg-info/entry_points.txt +0 -0
  60. {panther-4.1.3 → panther-4.2.0}/panther.egg-info/requires.txt +0 -0
  61. {panther-4.1.3 → panther-4.2.0}/panther.egg-info/top_level.txt +0 -0
  62. {panther-4.1.3 → panther-4.2.0}/pyproject.toml +0 -0
  63. {panther-4.1.3 → panther-4.2.0}/setup.cfg +0 -0
  64. {panther-4.1.3 → panther-4.2.0}/setup.py +0 -0
  65. {panther-4.1.3 → panther-4.2.0}/tests/test_authentication.py +0 -0
  66. {panther-4.1.3 → panther-4.2.0}/tests/test_background_tasks.py +0 -0
  67. {panther-4.1.3 → panther-4.2.0}/tests/test_caching.py +0 -0
  68. {panther-4.1.3 → panther-4.2.0}/tests/test_cli.py +0 -0
  69. {panther-4.1.3 → panther-4.2.0}/tests/test_events.py +0 -0
  70. {panther-4.1.3 → panther-4.2.0}/tests/test_generics.py +0 -0
  71. {panther-4.1.3 → panther-4.2.0}/tests/test_multipart.py +0 -0
  72. {panther-4.1.3 → panther-4.2.0}/tests/test_panel_apis.py +0 -0
  73. {panther-4.1.3 → panther-4.2.0}/tests/test_request.py +0 -0
  74. {panther-4.1.3 → panther-4.2.0}/tests/test_response.py +0 -0
  75. {panther-4.1.3 → panther-4.2.0}/tests/test_routing.py +0 -0
  76. {panther-4.1.3 → panther-4.2.0}/tests/test_run.py +0 -0
  77. {panther-4.1.3 → panther-4.2.0}/tests/test_serializer.py +0 -0
  78. {panther-4.1.3 → panther-4.2.0}/tests/test_status.py +0 -0
  79. {panther-4.1.3 → panther-4.2.0}/tests/test_throttling.py +0 -0
  80. {panther-4.1.3 → panther-4.2.0}/tests/test_utils.py +0 -0
  81. {panther-4.1.3 → panther-4.2.0}/tests/test_websockets.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: panther
3
- Version: 4.1.3
3
+ Version: 4.2.0
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,6 +1,6 @@
1
1
  from panther.main import Panther # noqa: F401
2
2
 
3
- __version__ = '4.1.3'
3
+ __version__ = '4.2.0'
4
4
 
5
5
 
6
6
  def version():
@@ -60,6 +60,10 @@ class API:
60
60
  async def wrapper(request: Request) -> Response:
61
61
  self.request = request
62
62
 
63
+ # 0. Preflight
64
+ if self.request.method == 'OPTIONS':
65
+ return self.options()
66
+
63
67
  # 1. Check Method
64
68
  if self.methods and self.request.method not in self.methods:
65
69
  raise MethodNotAllowedAPIError
@@ -141,6 +145,14 @@ class API:
141
145
  if self.input_model:
142
146
  self.request.validated_data = self.validate_input(model=self.input_model, request=self.request)
143
147
 
148
+ @classmethod
149
+ def options(cls):
150
+ headers = {
151
+ 'Access-Control-Allow-Methods': 'DELETE, GET, PATCH, POST, PUT, OPTIONS',
152
+ 'Access-Control-Allow-Headers': 'Accept, Authorization, User-Agent, Content-Type',
153
+ }
154
+ return Response(headers=headers)
155
+
144
156
  @classmethod
145
157
  def validate_input(cls, model, request: Request):
146
158
  if isinstance(request.data, bytes):
@@ -199,6 +211,8 @@ class GenericAPI:
199
211
  func = self.patch
200
212
  case 'DELETE':
201
213
  func = self.delete
214
+ case 'OPTIONS':
215
+ func = API.options
202
216
  case _:
203
217
  raise MethodNotAllowedAPIError
204
218
 
@@ -1,5 +1,6 @@
1
1
  from collections import namedtuple
2
2
  from collections.abc import Callable
3
+ from urllib.parse import parse_qsl
3
4
 
4
5
  from panther.db import Model
5
6
  from panther.exceptions import InvalidPathVariableAPIError
@@ -74,11 +75,7 @@ class BaseRequest:
74
75
  @property
75
76
  def query_params(self) -> dict:
76
77
  if self._params is None:
77
- self._params = {}
78
- if (query_string := self.scope['query_string']) != b'':
79
- for param in query_string.decode('utf-8').split('&'):
80
- k, *_, v = param.split('=')
81
- self._params[k] = v
78
+ self._params = {k: v for k, v in parse_qsl(self.scope['query_string'].decode('utf-8'))}
82
79
  return self._params
83
80
 
84
81
  @property
@@ -61,7 +61,7 @@ class CreateProject:
61
61
  },
62
62
  {
63
63
  'field': 'database',
64
- 'message': ' 0: PantherDB (File-Base, No Requirements)\n 1: MongoDB (Required `pymongo`)\n 2: No Database\nChoose Your Database (default is 0)',
64
+ 'message': ' 0: PantherDB (File-Base, No Requirements)\n 1: MongoDB (Required `motor`)\n 2: No Database\nChoose Your Database (default is 0)',
65
65
  'validation_func': lambda x: x in ['0', '1', '2'],
66
66
  'error_message': "Invalid Choice, '{}' not in ['0', '1', '2']",
67
67
  },
@@ -140,6 +140,7 @@ InfoThrottling = Throttling(rate=5, duration=timedelta(minutes=1))
140
140
 
141
141
  TIMEZONE = 'UTC'
142
142
 
143
+
143
144
  @API()
144
145
  async def hello_world_api():
145
146
  return {'detail': 'Hello World'}
@@ -61,7 +61,7 @@ class BaseMongoDBQuery(BaseQuery):
61
61
 
62
62
  @classmethod
63
63
  async def aggregate(cls, pipeline: Sequence[dict]) -> Iterable[dict]:
64
- return await db.session[cls.__name__].aggregate(pipeline)
64
+ return await db.session[cls.__name__].aggregate(pipeline).to_list(None)
65
65
 
66
66
  # # # # # Count # # # # #
67
67
  @classmethod
@@ -54,5 +54,5 @@ def _convert_to_object_id(_id):
54
54
  try:
55
55
  return bson.ObjectId(_id)
56
56
  except bson.objectid.InvalidId:
57
- msg = f'id={_id} is invalid bson.ObjectId'
58
- raise bson.errors.InvalidId(msg)
57
+ logger.warning(f'id={_id} is not a valid bson.ObjectId')
58
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: panther
3
- Version: 4.1.3
3
+ Version: 4.2.0
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
@@ -227,6 +227,21 @@ class _BaseDatabaseTestCase:
227
227
  for book in books:
228
228
  assert isinstance(book, Book)
229
229
 
230
+ async def test_aggregation(self):
231
+ # Insert Many
232
+ insert_count = await self._insert_many()
233
+
234
+ # Find All with aggregate
235
+ books = await Book.aggregate([])
236
+ _len = sum(1 for _ in books)
237
+
238
+ assert isinstance(books, list)
239
+
240
+ assert _len == insert_count
241
+ for book in books:
242
+ assert isinstance(book, dict)
243
+ assert {*book.keys()} == {'_id', 'name', 'author', 'pages_count'}
244
+
230
245
  # # # Count
231
246
  async def test_count_all(self):
232
247
  # Insert Many
@@ -502,6 +517,9 @@ class TestPantherDB(_BaseDatabaseTestCase, IsolatedAsyncioTestCase):
502
517
  def tearDown(self) -> None:
503
518
  Path(self.DB_PATH).unlink()
504
519
 
520
+ async def test_aggregation(self):
521
+ pass
522
+
505
523
 
506
524
  @pytest.mark.mongodb
507
525
  class TestMongoDB(_BaseDatabaseTestCase, IsolatedAsyncioTestCase):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes