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.
- {panther-4.1.3 → panther-4.2.0}/PKG-INFO +1 -1
- {panther-4.1.3 → panther-4.2.0}/panther/__init__.py +1 -1
- {panther-4.1.3 → panther-4.2.0}/panther/app.py +14 -0
- {panther-4.1.3 → panther-4.2.0}/panther/base_request.py +2 -5
- {panther-4.1.3 → panther-4.2.0}/panther/cli/create_command.py +1 -1
- {panther-4.1.3 → panther-4.2.0}/panther/cli/template.py +1 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/queries/mongodb_queries.py +1 -1
- {panther-4.1.3 → panther-4.2.0}/panther/db/utils.py +2 -2
- {panther-4.1.3 → panther-4.2.0}/panther.egg-info/PKG-INFO +1 -1
- {panther-4.1.3 → panther-4.2.0}/tests/test_database.py +18 -0
- {panther-4.1.3 → panther-4.2.0}/LICENSE +0 -0
- {panther-4.1.3 → panther-4.2.0}/README.md +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/_load_configs.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/_utils.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/authentications.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/background_tasks.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/base_websocket.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/caching.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/cli/__init__.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/cli/main.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/cli/monitor_command.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/cli/run_command.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/cli/utils.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/configs.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/__init__.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/connections.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/cursor.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/models.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/queries/__init__.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/queries/base_queries.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/queries/pantherdb_queries.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/db/queries/queries.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/events.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/exceptions.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/file_handler.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/generics.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/logging.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/main.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/middlewares/__init__.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/middlewares/base.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/monitoring.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/pagination.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/panel/__init__.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/panel/apis.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/panel/urls.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/panel/utils.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/permissions.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/request.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/response.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/routings.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/serializer.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/status.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/test.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/throttling.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/utils.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther/websocket.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther.egg-info/SOURCES.txt +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther.egg-info/dependency_links.txt +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther.egg-info/entry_points.txt +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther.egg-info/requires.txt +0 -0
- {panther-4.1.3 → panther-4.2.0}/panther.egg-info/top_level.txt +0 -0
- {panther-4.1.3 → panther-4.2.0}/pyproject.toml +0 -0
- {panther-4.1.3 → panther-4.2.0}/setup.cfg +0 -0
- {panther-4.1.3 → panther-4.2.0}/setup.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_authentication.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_background_tasks.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_caching.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_cli.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_events.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_generics.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_multipart.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_panel_apis.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_request.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_response.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_routing.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_run.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_serializer.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_status.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_throttling.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_utils.py +0 -0
- {panther-4.1.3 → panther-4.2.0}/tests/test_websockets.py +0 -0
@@ -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 `
|
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
|
},
|
@@ -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
|
@@ -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
|
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
|