muffin-rest 9.2.0__py3-none-any.whl → 9.4.0__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.
muffin_rest/filters.py CHANGED
@@ -1,17 +1,20 @@
1
1
  """Support API filters."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import operator
5
6
  from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Mapping, Optional # py39
6
7
 
7
8
  import marshmallow as ma
8
- from asgi_tools._compat import json_loads # type: ignore[]
9
+ from asgi_tools._compat import json_loads
9
10
 
10
11
  from .utils import Mutate, Mutator
11
12
 
12
13
  if TYPE_CHECKING:
13
14
  from muffin import Request
14
15
 
16
+ from muffin_rest.types import TFilterOps, TFilterValue
17
+
15
18
  from .types import TVCollection
16
19
 
17
20
  FILTERS_PARAM = "where"
@@ -87,7 +90,7 @@ class Filter(Mutate):
87
90
 
88
91
  return ops, collection
89
92
 
90
- async def filter(self, collection, *ops: tuple[Callable, Any], **_) -> Any:
93
+ async def filter(self, collection, *ops: TFilterValue) -> Any:
91
94
  """Apply the filter to collection."""
92
95
 
93
96
  def validator(obj):
@@ -95,12 +98,22 @@ class Filter(Mutate):
95
98
 
96
99
  return [item for item in collection if validator(item)]
97
100
 
98
- def parse(self, data: Mapping):
101
+ def get_simple_value(self, ops: TFilterOps) -> Any:
102
+ """Get simple value from filter's data.
103
+
104
+ In case of simple filter, return the value.
105
+ """
106
+ if not ops:
107
+ return None
108
+
109
+ return ops[0][1]
110
+
111
+ def parse(self, data: Mapping) -> TFilterOps:
99
112
  """Parse operator and value from filter's data."""
100
113
  value = data.get(self.name, ma.missing)
101
114
  return tuple(self._parse(value))
102
115
 
103
- def _parse(self, value):
116
+ def _parse(self, value) -> Iterable[TFilterValue]:
104
117
  deserialize = self.schema_field.deserialize
105
118
  if isinstance(value, dict):
106
119
  for op, val in value.items():
@@ -1,8 +1,9 @@
1
1
  """Support filters for Mongo."""
2
2
 
3
- from typing import Any, Callable, ClassVar
3
+ from typing import ClassVar
4
4
 
5
5
  from muffin_rest.filters import Filter, Filters
6
+ from muffin_rest.types import TFilterValue
6
7
 
7
8
 
8
9
  class MongoFilter(Filter):
@@ -21,7 +22,7 @@ class MongoFilter(Filter):
21
22
  "$ends": lambda _, v: ("$regex", f"{ v }$"),
22
23
  }
23
24
 
24
- async def filter(self, collection, *ops: tuple[Callable, Any], **_):
25
+ async def filter(self, collection, *ops: TFilterValue):
25
26
  """Apply the filter."""
26
27
  return collection.find({self.field: dict(op(self.name, v) for op, v in ops)})
27
28
 
@@ -1,9 +1,10 @@
1
1
  """Support filters for Peewee ORM."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import operator
5
6
  from functools import reduce
6
- from typing import Any, Callable, ClassVar, Union, cast
7
+ from typing import TYPE_CHECKING, ClassVar, Union, cast
7
8
 
8
9
  from peewee import ColumnBase, Field, ModelSelect
9
10
 
@@ -11,6 +12,9 @@ from muffin_rest.filters import Filter, Filters
11
12
 
12
13
  from .utils import get_model_field_by_name
13
14
 
15
+ if TYPE_CHECKING:
16
+ from muffin_rest.types import TFilterValue
17
+
14
18
 
15
19
  class PWFilter(Filter):
16
20
  """Support Peewee."""
@@ -33,9 +37,7 @@ class PWFilter(Filter):
33
37
 
34
38
  list_ops = (*Filter.list_ops, "$between")
35
39
 
36
- async def filter(
37
- self, collection: ModelSelect, *ops: tuple[Callable, Any], **kwargs
38
- ) -> ModelSelect:
40
+ async def filter(self, collection: ModelSelect, *ops: TFilterValue) -> ModelSelect:
39
41
  """Apply the filters to Peewee QuerySet.."""
40
42
  column = self.field
41
43
  if isinstance(column, ColumnBase):
@@ -2,13 +2,15 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import TYPE_CHECKING, Any, Callable, ClassVar, Union, cast
5
+ from typing import TYPE_CHECKING, Any, ClassVar, Union, cast
6
6
 
7
7
  from sqlalchemy import Column
8
8
 
9
9
  from muffin_rest.filters import Filter, Filters
10
10
 
11
11
  if TYPE_CHECKING:
12
+ from muffin_rest.types import TFilterValue
13
+
12
14
  from .types import TVCollection
13
15
 
14
16
 
@@ -29,17 +31,15 @@ class SAFilter(Filter):
29
31
 
30
32
  list_ops = (*Filter.list_ops, "$between")
31
33
 
32
- async def filter(
33
- self, collection: TVCollection, *ops: tuple[Callable, Any], **kwargs
34
- ) -> TVCollection:
34
+ async def filter(self, collection: TVCollection, *ops: TFilterValue) -> TVCollection:
35
35
  """Apply the filters to SQLAlchemy Select."""
36
36
  column = self.field
37
37
  if ops and column is not None:
38
- return self.query(collection, column, *ops, **kwargs)
38
+ return self.query(collection, column, *ops)
39
39
 
40
40
  return collection
41
41
 
42
- def query(self, select: TVCollection, column: Column, *ops, **_) -> TVCollection:
42
+ def query(self, select: TVCollection, column: Column, *ops: TFilterValue) -> TVCollection:
43
43
  """Filter a select."""
44
44
  return select.where(*[op(column, val) for op, val in ops])
45
45
 
muffin_rest/types.py CHANGED
@@ -19,3 +19,6 @@ TAuth = Callable[[Request], Awaitable]
19
19
  TVAuth = TypeVar("TVAuth", bound=TAuth)
20
20
  TVHandler = TypeVar("TVHandler", bound=type["RESTBase"])
21
21
  TSchemaRes = dict[str, Any]
22
+
23
+ TFilterValue = tuple[Callable, Any]
24
+ TFilterOps = tuple[TFilterValue, ...]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: muffin-rest
3
- Version: 9.2.0
3
+ Version: 9.4.0
4
4
  Summary: The package provides enhanced support for writing REST APIs with Muffin framework
5
5
  Home-page: https://github.com/klen/muffin-rest
6
6
  License: MIT
@@ -1,12 +1,12 @@
1
1
  muffin_rest/__init__.py,sha256=NBZeOEJgQHtFFhVgd9d0fpApFRgU405sbm0cu1y1MOU,1242
2
2
  muffin_rest/api.py,sha256=zssoHjqTsa8UCAyxj6TxQVluYPX9Sigyiph6SRxBY6I,3870
3
3
  muffin_rest/errors.py,sha256=mxEBhNPo3pwpG2em6zaQonbfRgHFBJ3I8WunVYWDjvM,1163
4
- muffin_rest/filters.py,sha256=MARP_WsJslncahlgZLTImigl0RTxBtb0jmZbXfJ0c6Y,5637
4
+ muffin_rest/filters.py,sha256=hc-fhBODwrgJM_CvXNtTVH6jIOkjLog8En0iKKYXAGU,5947
5
5
  muffin_rest/handler.py,sha256=3efL8-AbxR0oHEwySfWSyfRuxCWyJOwDaYAhUzg6f-0,10772
6
6
  muffin_rest/limits.py,sha256=pA5hnDQgrP-euDGjAoczlT_b7Dxzw5btQ-3okkHYKSA,1855
7
7
  muffin_rest/marshmallow.py,sha256=jWsZeMj3KslbGGgzEMo8-e5eeuGhmqFolL0mIEquylc,789
8
8
  muffin_rest/mongo/__init__.py,sha256=SiYSbX6ySJl43fw9aGREIs8ZsS8Qk_ieizoPOj4DjJc,4656
9
- muffin_rest/mongo/filters.py,sha256=4TgExaUhJiHkogiZLqjtT13A0O-Uvwfd5AesVfTY2Io,949
9
+ muffin_rest/mongo/filters.py,sha256=yIxIDVqMn6SoDgVhCqiTxYetw0hoaf_3jIvX2Vnizok,964
10
10
  muffin_rest/mongo/schema.py,sha256=y4OEPQnlV_COTIIQ3cKmpqDpD2r18eAWn0rijQldWm0,1205
11
11
  muffin_rest/mongo/sorting.py,sha256=iJBnaFwE7g_JMwpGpQkoqSqbQK9XULx1K3skiRRgLgY,870
12
12
  muffin_rest/mongo/types.py,sha256=jaODScgwwYbzHis3DY4bPzU1ahiMJMSwquH5_Thi-Gg,200
@@ -14,7 +14,7 @@ muffin_rest/mongo/utils.py,sha256=mNkLM-D6gqOA9YW2Qdw0DvE2N4LRmxLAiPMKH9WLttM,39
14
14
  muffin_rest/openapi.py,sha256=0QU7qrfBjGl0vl378SJC5boZZI2ogddl45fS9WL4Axw,8751
15
15
  muffin_rest/options.py,sha256=reHbd2o-F6bKEKc8bznzj0TMY2vzjK6Yt1qOny7kt_w,2691
16
16
  muffin_rest/peewee/__init__.py,sha256=94DSj_ftT6fbPksHlBv40AH2HWaiZommUFOMN2jd9a4,129
17
- muffin_rest/peewee/filters.py,sha256=oghjKwurNCyFUYT0r2TVu2Nd1SIalRsmbU4_RbaoXLs,2440
17
+ muffin_rest/peewee/filters.py,sha256=p813eJqyTkAhmS3C1P8rWFWb9Tl33OtADjgLctqKnns,2475
18
18
  muffin_rest/peewee/handler.py,sha256=Tk20ChTGkhzSF0K1-TFruPfXJyHfJE_fDKcQqGQeoAU,5297
19
19
  muffin_rest/peewee/openapi.py,sha256=lDnLnoXi33p0YeFVwRgaVrndyrG2XL93RH-BzbxinOY,1105
20
20
  muffin_rest/peewee/options.py,sha256=TimJtErC9e8B7BRiEkHiBZd71_bZbYr-FE2PIlQvfH0,1455
@@ -27,13 +27,13 @@ muffin_rest/redoc.html,sha256=GtuHIMvTuSi8Ro6bgI-G8VB94AljMyfjcZseqtBmGCY,559
27
27
  muffin_rest/schemas.py,sha256=BW3dF82C6Q6STs4tZjej1x8Ii1rI3EZUJZR4mNNKmu4,875
28
28
  muffin_rest/sorting.py,sha256=7k7dxElnEGiwvdfDivzcoLnAOXqpQoK52H-ss79Gw0g,2813
29
29
  muffin_rest/sqlalchemy/__init__.py,sha256=9MSvOXWP6665LiA5O1Icl2V05bpz6Ex5sUHB9YWKLvE,6393
30
- muffin_rest/sqlalchemy/filters.py,sha256=oVz3he9P_KiYE4fM3Wjka2IUmhkf4gHDOVRzKlz0SA0,2484
30
+ muffin_rest/sqlalchemy/filters.py,sha256=ejqjEZU0vqvnLwG0sX7QV3RjcXI0a2Ro_A34AAiGMEc,2489
31
31
  muffin_rest/sqlalchemy/sorting.py,sha256=YlFKpIet4TUy7fJ2UBLC8b9lAOwY66QBpPDDApbyh8M,1643
32
32
  muffin_rest/sqlalchemy/types.py,sha256=Exm-zAQCtPAwXvYcCTtPRqSa-wTEWRcH_v2YSsJkB6s,198
33
33
  muffin_rest/swagger.html,sha256=2uGLu_KpkYf925KnDKHBJmV9pm6OHn5C3BWScESsUS8,1736
34
- muffin_rest/types.py,sha256=lU0tAaDu9sKm-30RM1_qOx-hOYEkNRaA72LdWDvg72g,491
34
+ muffin_rest/types.py,sha256=m27-g6BI7qdSWGym4fWALBJa2ZpWR0_m0nlrDx7iTCo,566
35
35
  muffin_rest/utils.py,sha256=c08E4HJ4SLYC-91GKPEbsyKTZ4sZbTN4qDqJbNg_HTE,2076
36
- muffin_rest-9.2.0.dist-info/LICENSE,sha256=xHPkOZhjyKBMOwXpWn9IB_BVLjrrMxv2M9slKkHj2hM,1082
37
- muffin_rest-9.2.0.dist-info/METADATA,sha256=ZB8W02vkcIb8ZrwPQEGeF5MH7P9A2g9ZMfJ-943x1WE,4134
38
- muffin_rest-9.2.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
39
- muffin_rest-9.2.0.dist-info/RECORD,,
36
+ muffin_rest-9.4.0.dist-info/LICENSE,sha256=xHPkOZhjyKBMOwXpWn9IB_BVLjrrMxv2M9slKkHj2hM,1082
37
+ muffin_rest-9.4.0.dist-info/METADATA,sha256=7LF2JbYYQ4k9VusfwGZolZi9oY3rHNIIC3TQs03tUFM,4134
38
+ muffin_rest-9.4.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
39
+ muffin_rest-9.4.0.dist-info/RECORD,,