starmallow 0.4.0__py3-none-any.whl → 0.5.1__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.
starmallow/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.4.0"
1
+ __version__ = "0.5.1"
2
2
 
3
3
  from .applications import StarMallow
4
4
  from .exceptions import RequestValidationError
@@ -251,6 +251,7 @@ class StarMallow(Starlette):
251
251
  name: str = None,
252
252
  include_in_schema: bool = True,
253
253
  status_code: Optional[int] = None,
254
+ middleware: Sequence[Middleware] | None = None,
254
255
  request_class: Type[Request] = Default(Request),
255
256
  response_model: Optional[Type[Any]] = None,
256
257
  response_class: Type[Response] = JSONResponse,
@@ -276,6 +277,7 @@ class StarMallow(Starlette):
276
277
  name=name,
277
278
  include_in_schema=include_in_schema,
278
279
  status_code=status_code,
280
+ middleware=middleware,
279
281
  request_class=request_class,
280
282
  response_model=response_model,
281
283
  response_class=response_class,
@@ -298,6 +300,7 @@ class StarMallow(Starlette):
298
300
  name: str = None,
299
301
  include_in_schema: bool = True,
300
302
  status_code: Optional[int] = None,
303
+ middleware: Sequence[Middleware] | None = None,
301
304
  request_class: Type[Request] = Default(Request),
302
305
  response_model: Optional[Type[Any]] = None,
303
306
  response_class: Type[Response] = JSONResponse,
@@ -322,6 +325,7 @@ class StarMallow(Starlette):
322
325
  name=name,
323
326
  include_in_schema=include_in_schema,
324
327
  status_code=status_code,
328
+ middleware=middleware,
325
329
  request_class=request_class,
326
330
  response_model=response_model,
327
331
  response_class=response_class,
@@ -386,6 +390,7 @@ class StarMallow(Starlette):
386
390
  name: str = None,
387
391
  include_in_schema: bool = True,
388
392
  status_code: Optional[int] = None,
393
+ middleware: Sequence[Middleware] | None = None,
389
394
  request_class: Type[Request] = Default(Request),
390
395
  response_model: Optional[Type[Any]] = None,
391
396
  response_class: Type[Response] = JSONResponse,
@@ -409,6 +414,7 @@ class StarMallow(Starlette):
409
414
  name=name,
410
415
  include_in_schema=include_in_schema,
411
416
  status_code=status_code,
417
+ middleware=middleware,
412
418
  request_class=request_class,
413
419
  response_model=response_model,
414
420
  response_class=response_class,
@@ -430,6 +436,7 @@ class StarMallow(Starlette):
430
436
  name: str = None,
431
437
  include_in_schema: bool = True,
432
438
  status_code: Optional[int] = None,
439
+ middleware: Sequence[Middleware] | None = None,
433
440
  request_class: Type[Request] = Default(Request),
434
441
  response_model: Optional[Type[Any]] = None,
435
442
  response_class: Type[Response] = JSONResponse,
@@ -453,6 +460,7 @@ class StarMallow(Starlette):
453
460
  name=name,
454
461
  include_in_schema=include_in_schema,
455
462
  status_code=status_code,
463
+ middleware=middleware,
456
464
  request_class=request_class,
457
465
  response_model=response_model,
458
466
  response_class=response_class,
@@ -474,6 +482,7 @@ class StarMallow(Starlette):
474
482
  name: str = None,
475
483
  include_in_schema: bool = True,
476
484
  status_code: Optional[int] = None,
485
+ middleware: Sequence[Middleware] | None = None,
477
486
  request_class: Type[Request] = Default(Request),
478
487
  response_model: Optional[Type[Any]] = None,
479
488
  response_class: Type[Response] = JSONResponse,
@@ -497,6 +506,7 @@ class StarMallow(Starlette):
497
506
  name=name,
498
507
  include_in_schema=include_in_schema,
499
508
  status_code=status_code,
509
+ middleware=middleware,
500
510
  request_class=request_class,
501
511
  response_model=response_model,
502
512
  response_class=response_class,
@@ -518,6 +528,7 @@ class StarMallow(Starlette):
518
528
  name: str = None,
519
529
  include_in_schema: bool = True,
520
530
  status_code: Optional[int] = None,
531
+ middleware: Sequence[Middleware] | None = None,
521
532
  request_class: Type[Request] = Default(Request),
522
533
  response_model: Optional[Type[Any]] = None,
523
534
  response_class: Type[Response] = JSONResponse,
@@ -541,6 +552,7 @@ class StarMallow(Starlette):
541
552
  name=name,
542
553
  include_in_schema=include_in_schema,
543
554
  status_code=status_code,
555
+ middleware=middleware,
544
556
  request_class=request_class,
545
557
  response_model=response_model,
546
558
  response_class=response_class,
@@ -562,6 +574,7 @@ class StarMallow(Starlette):
562
574
  name: str = None,
563
575
  include_in_schema: bool = True,
564
576
  status_code: Optional[int] = None,
577
+ middleware: Sequence[Middleware] | None = None,
565
578
  request_class: Type[Request] = Default(Request),
566
579
  response_model: Optional[Type[Any]] = None,
567
580
  response_class: Type[Response] = JSONResponse,
@@ -585,6 +598,7 @@ class StarMallow(Starlette):
585
598
  name=name,
586
599
  include_in_schema=include_in_schema,
587
600
  status_code=status_code,
601
+ middleware=middleware,
588
602
  request_class=request_class,
589
603
  response_model=response_model,
590
604
  response_class=response_class,
@@ -606,6 +620,7 @@ class StarMallow(Starlette):
606
620
  name: str = None,
607
621
  include_in_schema: bool = True,
608
622
  status_code: Optional[int] = None,
623
+ middleware: Sequence[Middleware] | None = None,
609
624
  request_class: Type[Request] = Default(Request),
610
625
  response_model: Optional[Type[Any]] = None,
611
626
  response_class: Type[Response] = JSONResponse,
@@ -629,6 +644,7 @@ class StarMallow(Starlette):
629
644
  name=name,
630
645
  include_in_schema=include_in_schema,
631
646
  status_code=status_code,
647
+ middleware=middleware,
632
648
  request_class=request_class,
633
649
  response_model=response_model,
634
650
  response_class=response_class,
@@ -650,6 +666,7 @@ class StarMallow(Starlette):
650
666
  name: str = None,
651
667
  include_in_schema: bool = True,
652
668
  status_code: Optional[int] = None,
669
+ middleware: Sequence[Middleware] | None = None,
653
670
  request_class: Type[Request] = Default(Request),
654
671
  response_model: Optional[Type[Any]] = None,
655
672
  response_class: Type[Response] = JSONResponse,
@@ -673,6 +690,7 @@ class StarMallow(Starlette):
673
690
  name=name,
674
691
  include_in_schema=include_in_schema,
675
692
  status_code=status_code,
693
+ middleware=middleware,
676
694
  request_class=request_class,
677
695
  response_model=response_model,
678
696
  response_class=response_class,
@@ -694,6 +712,7 @@ class StarMallow(Starlette):
694
712
  name: str = None,
695
713
  include_in_schema: bool = True,
696
714
  status_code: Optional[int] = None,
715
+ middleware: Sequence[Middleware] | None = None,
697
716
  request_class: Type[Request] = Default(Request),
698
717
  response_model: Optional[Type[Any]] = None,
699
718
  response_class: Type[Response] = JSONResponse,
@@ -717,6 +736,7 @@ class StarMallow(Starlette):
717
736
  name=name,
718
737
  include_in_schema=include_in_schema,
719
738
  status_code=status_code,
739
+ middleware=middleware,
720
740
  request_class=request_class,
721
741
  response_model=response_model,
722
742
  response_class=response_class,
starmallow/decorators.py CHANGED
@@ -1,7 +1,8 @@
1
1
  from dataclasses import dataclass, field
2
2
  from enum import Enum
3
- from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Type, Union
3
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Type, Union
4
4
 
5
+ from starlette.middleware import Middleware
5
6
  from starlette.requests import Request
6
7
  from starlette.responses import Response
7
8
  from starlette.routing import BaseRoute
@@ -20,6 +21,7 @@ class EndpointOptions:
20
21
  name: str = None
21
22
  include_in_schema: bool = True
22
23
  status_code: Optional[int] = None
24
+ middleware: Sequence[Middleware] | None = None
23
25
  deprecated: Optional[bool] = None
24
26
  request_class: Type[Request] = Request
25
27
  response_model: Optional[Type[Any]] = None
@@ -40,6 +42,7 @@ class EndpointOptions:
40
42
  tags: Optional[List[Union[str, Enum]]] = None
41
43
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
42
44
  openapi_extra: Optional[Dict[str, Any]] = None
45
+ route_class: Optional[Type["APIRoute"]] = None
43
46
 
44
47
 
45
48
  def route(
@@ -47,6 +50,7 @@ def route(
47
50
  name: str = None,
48
51
  include_in_schema: bool = True,
49
52
  status_code: Optional[int] = None,
53
+ middleware: Sequence[Middleware] | None = None,
50
54
  deprecated: Optional[bool] = None,
51
55
  request_class: Type[Request] = Default(Request),
52
56
  response_model: Optional[Type[Any]] = None,
@@ -65,6 +69,7 @@ def route(
65
69
  tags: Optional[List[Union[str, Enum]]] = None,
66
70
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
67
71
  openapi_extra: Optional[Dict[str, Any]] = None,
72
+ route_class: Optional[Type["APIRoute"]] = None,
68
73
  ) -> Callable[[DecoratedCallable], DecoratedCallable]:
69
74
  '''
70
75
  Intended to be used with APIHTTPEndpoint to override options on a per method basis
@@ -75,6 +80,7 @@ def route(
75
80
  name=name,
76
81
  include_in_schema=include_in_schema,
77
82
  status_code=status_code,
83
+ middleware=middleware,
78
84
  deprecated=deprecated,
79
85
  request_class=request_class,
80
86
  response_model=response_model,
@@ -88,6 +94,7 @@ def route(
88
94
  generate_unique_id_function=generate_unique_id_function,
89
95
  openapi_extra=openapi_extra,
90
96
  tags=tags,
97
+ route_class=route_class,
91
98
  )
92
99
  return func
93
100
  return decorator
starmallow/params.py CHANGED
@@ -159,6 +159,7 @@ class Header(Param):
159
159
  title=title,
160
160
  )
161
161
 
162
+
162
163
  class Cookie(Param):
163
164
  in_ = ParamType.cookie
164
165
 
starmallow/routing.py CHANGED
@@ -11,6 +11,7 @@ from typing import (
11
11
  Dict,
12
12
  List,
13
13
  Optional,
14
+ Sequence,
14
15
  Set,
15
16
  Tuple,
16
17
  Type,
@@ -20,6 +21,7 @@ from typing import (
20
21
  import marshmallow as ma
21
22
  from starlette import routing
22
23
  from starlette.concurrency import run_in_threadpool
24
+ from starlette.middleware import Middleware
23
25
  from starlette.requests import Request
24
26
  from starlette.responses import Response
25
27
  from starlette.routing import (
@@ -213,6 +215,7 @@ class APIRoute(routing.Route, EndpointMixin):
213
215
  name: Optional[str] = None,
214
216
  methods: Optional[Union[Set[str], List[str]]] = None,
215
217
  include_in_schema: bool = True,
218
+ middleware: Sequence[Middleware] | None = None,
216
219
  status_code: Optional[int] = None,
217
220
  deprecated: Optional[bool] = None,
218
221
  request_class: Union[Type[Request], DefaultPlaceholder] = Default(
@@ -342,7 +345,14 @@ class APIRoute(routing.Route, EndpointMixin):
342
345
  route=self,
343
346
  )
344
347
 
345
- self.app = request_response(get_request_handler(self.endpoint_model), self.request_class)
348
+ self.middleware = middleware # Store for include_router
349
+ self.app = request_response(self.get_route_handler(), self.request_class)
350
+ if middleware is not None:
351
+ for cls, args, kwargs in reversed(middleware):
352
+ self.app = cls(app=self.app, *args, **kwargs) # noqa: B026
353
+
354
+ def get_route_handler(self):
355
+ return get_request_handler(self.endpoint_model)
346
356
 
347
357
 
348
358
  class APIRouter(routing.Router):
@@ -361,9 +371,11 @@ class APIRouter(routing.Router):
361
371
  generate_unique_id,
362
372
  ),
363
373
  prefix: str = "",
374
+ route_class: Optional[Type[APIRoute]] = APIRoute,
375
+ middleware: Sequence[Middleware] | None = None,
364
376
  **kwargs,
365
377
  ) -> None:
366
- super().__init__(*args, **kwargs)
378
+ super().__init__(*args, middleware=middleware, **kwargs)
367
379
 
368
380
  self.tags: List[Union[str, Enum]] = tags or []
369
381
  self.default_request_class = default_request_class
@@ -374,6 +386,8 @@ class APIRouter(routing.Router):
374
386
  self.callbacks = callbacks or []
375
387
  self.generate_unique_id_function = generate_unique_id_function
376
388
  self.prefix = prefix
389
+ self.route_class = route_class
390
+ self.middleware = middleware
377
391
 
378
392
  def route(
379
393
  self,
@@ -403,6 +417,7 @@ class APIRouter(routing.Router):
403
417
  name: str = None,
404
418
  include_in_schema: bool = True,
405
419
  status_code: Optional[int] = None,
420
+ middleware: Sequence[Middleware] | None = None,
406
421
  deprecated: Optional[bool] = None,
407
422
  request_class: Type[Request] = Default(Request),
408
423
  response_model: Optional[Type[Any]] = None,
@@ -421,7 +436,9 @@ class APIRouter(routing.Router):
421
436
  tags: Optional[List[Union[str, Enum]]] = None,
422
437
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
423
438
  openapi_extra: Optional[Dict[str, Any]] = None,
439
+ route_class: Optional[Type[APIRoute]] = None,
424
440
  ) -> None:
441
+ route_class = route_class or self.route_class
425
442
 
426
443
  current_tags = self.tags.copy()
427
444
  if tags:
@@ -443,13 +460,15 @@ class APIRouter(routing.Router):
443
460
  if endpoint_options.tags:
444
461
  method_tags.extend(endpoint_options.tags)
445
462
 
446
- route = APIRoute(
463
+ endpoint_route_class = endpoint_options.route_class or route_class
464
+ route = endpoint_route_class(
447
465
  self.prefix + path,
448
466
  endpoint_function,
449
467
  methods=[method],
450
468
  name=endpoint_options.name or name,
451
469
  include_in_schema=endpoint_options.include_in_schema and include_in_schema and self.include_in_schema,
452
470
  status_code=endpoint_options.status_code or status_code,
471
+ middleware=endpoint_options.middleware or middleware,
453
472
  deprecated=endpoint_options.deprecated or deprecated or self.deprecated,
454
473
  request_class=endpoint_options.request_class or request_class,
455
474
  response_model=endpoint_options.response_model or response_model,
@@ -468,13 +487,14 @@ class APIRouter(routing.Router):
468
487
  self.routes.append(route)
469
488
 
470
489
  else:
471
- route = APIRoute(
490
+ route = route_class(
472
491
  self.prefix + path,
473
492
  endpoint,
474
493
  methods=methods,
475
494
  name=name,
476
495
  include_in_schema=include_in_schema and self.include_in_schema,
477
496
  status_code=status_code,
497
+ middleware=middleware,
478
498
  deprecated=deprecated or self.deprecated,
479
499
  request_class=request_class,
480
500
  response_model=response_model,
@@ -500,6 +520,7 @@ class APIRouter(routing.Router):
500
520
  name: str = None,
501
521
  include_in_schema: bool = True,
502
522
  status_code: Optional[int] = None,
523
+ middleware: Sequence[Middleware] | None = None,
503
524
  deprecated: Optional[bool] = None,
504
525
  request_class: Type[Request] = Default(Request),
505
526
  response_model: Optional[Type[Any]] = None,
@@ -518,6 +539,7 @@ class APIRouter(routing.Router):
518
539
  tags: Optional[List[Union[str, Enum]]] = None,
519
540
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
520
541
  openapi_extra: Optional[Dict[str, Any]] = None,
542
+ route_class: Optional[Type[APIRoute]] = None,
521
543
  ) -> Callable[[DecoratedCallable], DecoratedCallable]:
522
544
  def decorator(func: DecoratedCallable) -> DecoratedCallable:
523
545
  self.add_api_route(
@@ -527,6 +549,7 @@ class APIRouter(routing.Router):
527
549
  name=name,
528
550
  include_in_schema=include_in_schema,
529
551
  status_code=status_code,
552
+ middleware=middleware,
530
553
  deprecated=deprecated,
531
554
  request_class=request_class,
532
555
  response_model=response_model,
@@ -540,6 +563,7 @@ class APIRouter(routing.Router):
540
563
  generate_unique_id_function=generate_unique_id_function,
541
564
  openapi_extra=openapi_extra,
542
565
  tags=tags,
566
+ route_class=route_class,
543
567
  )
544
568
  return func
545
569
  return decorator
@@ -633,11 +657,19 @@ class APIRouter(routing.Router):
633
657
  generate_unique_id_function,
634
658
  self.generate_unique_id_function,
635
659
  )
660
+
661
+ middleware = []
662
+ if router.middleware:
663
+ middleware.extend(router.middleware)
664
+ if route.middleware:
665
+ middleware.extend(route.middleware)
666
+
636
667
  self.add_api_route(
637
668
  prefix + route.path,
638
669
  route.endpoint,
639
670
  response_model=route.response_model,
640
671
  status_code=route.status_code,
672
+ middleware=middleware,
641
673
  tags=current_tags,
642
674
  summary=route.summary,
643
675
  description=route.description,
@@ -657,6 +689,7 @@ class APIRouter(routing.Router):
657
689
  name=route.name,
658
690
  openapi_extra=route.openapi_extra,
659
691
  generate_unique_id_function=current_generate_unique_id,
692
+ route_class=route.__class__,
660
693
  )
661
694
  elif isinstance(route, routing.Route):
662
695
  methods = list(route.methods or [])
@@ -688,6 +721,7 @@ class APIRouter(routing.Router):
688
721
  name: str = None,
689
722
  include_in_schema: bool = True,
690
723
  status_code: Optional[int] = None,
724
+ middleware: Sequence[Middleware] | None = None,
691
725
  deprecated: Optional[bool] = None,
692
726
  request_class: Type[Request] = Default(Request),
693
727
  response_model: Optional[Type[Any]] = None,
@@ -706,6 +740,7 @@ class APIRouter(routing.Router):
706
740
  tags: Optional[List[Union[str, Enum]]] = None,
707
741
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
708
742
  openapi_extra: Optional[Dict[str, Any]] = None,
743
+ route_class: Optional[Type[APIRoute]] = None,
709
744
  ):
710
745
  return self.api_route(
711
746
  path,
@@ -713,6 +748,7 @@ class APIRouter(routing.Router):
713
748
  name=name,
714
749
  include_in_schema=include_in_schema,
715
750
  status_code=status_code,
751
+ middleware=middleware,
716
752
  deprecated=deprecated,
717
753
  request_class=request_class,
718
754
  response_model=response_model,
@@ -726,6 +762,7 @@ class APIRouter(routing.Router):
726
762
  generate_unique_id_function=generate_unique_id_function,
727
763
  openapi_extra=openapi_extra,
728
764
  tags=tags,
765
+ route_class=route_class,
729
766
  )
730
767
 
731
768
  def put(
@@ -735,6 +772,7 @@ class APIRouter(routing.Router):
735
772
  name: str = None,
736
773
  include_in_schema: bool = True,
737
774
  status_code: Optional[int] = None,
775
+ middleware: Sequence[Middleware] | None = None,
738
776
  deprecated: Optional[bool] = None,
739
777
  request_class: Type[Request] = Default(Request),
740
778
  response_model: Optional[Type[Any]] = None,
@@ -753,6 +791,7 @@ class APIRouter(routing.Router):
753
791
  tags: Optional[List[Union[str, Enum]]] = None,
754
792
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
755
793
  openapi_extra: Optional[Dict[str, Any]] = None,
794
+ route_class: Optional[Type[APIRoute]] = None,
756
795
  ):
757
796
  return self.api_route(
758
797
  path,
@@ -760,6 +799,7 @@ class APIRouter(routing.Router):
760
799
  name=name,
761
800
  include_in_schema=include_in_schema,
762
801
  status_code=status_code,
802
+ middleware=middleware,
763
803
  deprecated=deprecated,
764
804
  request_class=request_class,
765
805
  response_model=response_model,
@@ -773,6 +813,7 @@ class APIRouter(routing.Router):
773
813
  generate_unique_id_function=generate_unique_id_function,
774
814
  openapi_extra=openapi_extra,
775
815
  tags=tags,
816
+ route_class=route_class,
776
817
  )
777
818
 
778
819
  def post(
@@ -782,6 +823,7 @@ class APIRouter(routing.Router):
782
823
  name: str = None,
783
824
  include_in_schema: bool = True,
784
825
  status_code: Optional[int] = None,
826
+ middleware: Sequence[Middleware] | None = None,
785
827
  deprecated: Optional[bool] = None,
786
828
  request_class: Type[Request] = Default(Request),
787
829
  response_model: Optional[Type[Any]] = None,
@@ -800,6 +842,7 @@ class APIRouter(routing.Router):
800
842
  tags: Optional[List[Union[str, Enum]]] = None,
801
843
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
802
844
  openapi_extra: Optional[Dict[str, Any]] = None,
845
+ route_class: Optional[Type[APIRoute]] = None,
803
846
  ):
804
847
  return self.api_route(
805
848
  path,
@@ -807,6 +850,7 @@ class APIRouter(routing.Router):
807
850
  name=name,
808
851
  include_in_schema=include_in_schema,
809
852
  status_code=status_code,
853
+ middleware=middleware,
810
854
  deprecated=deprecated,
811
855
  request_class=request_class,
812
856
  response_model=response_model,
@@ -820,6 +864,7 @@ class APIRouter(routing.Router):
820
864
  generate_unique_id_function=generate_unique_id_function,
821
865
  openapi_extra=openapi_extra,
822
866
  tags=tags,
867
+ route_class=route_class,
823
868
  )
824
869
 
825
870
  def delete(
@@ -829,6 +874,7 @@ class APIRouter(routing.Router):
829
874
  name: str = None,
830
875
  include_in_schema: bool = True,
831
876
  status_code: Optional[int] = None,
877
+ middleware: Sequence[Middleware] | None = None,
832
878
  deprecated: Optional[bool] = None,
833
879
  request_class: Type[Request] = Default(Request),
834
880
  response_model: Optional[Type[Any]] = None,
@@ -847,6 +893,7 @@ class APIRouter(routing.Router):
847
893
  tags: Optional[List[Union[str, Enum]]] = None,
848
894
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
849
895
  openapi_extra: Optional[Dict[str, Any]] = None,
896
+ route_class: Optional[Type[APIRoute]] = None,
850
897
  ):
851
898
  return self.api_route(
852
899
  path,
@@ -854,6 +901,7 @@ class APIRouter(routing.Router):
854
901
  name=name,
855
902
  include_in_schema=include_in_schema,
856
903
  status_code=status_code,
904
+ middleware=middleware,
857
905
  deprecated=deprecated,
858
906
  request_class=request_class,
859
907
  response_model=response_model,
@@ -867,6 +915,7 @@ class APIRouter(routing.Router):
867
915
  generate_unique_id_function=generate_unique_id_function,
868
916
  openapi_extra=openapi_extra,
869
917
  tags=tags,
918
+ route_class=route_class,
870
919
  )
871
920
 
872
921
  def options(
@@ -876,6 +925,7 @@ class APIRouter(routing.Router):
876
925
  name: str = None,
877
926
  include_in_schema: bool = True,
878
927
  status_code: Optional[int] = None,
928
+ middleware: Sequence[Middleware] | None = None,
879
929
  deprecated: Optional[bool] = None,
880
930
  request_class: Type[Request] = Default(Request),
881
931
  response_model: Optional[Type[Any]] = None,
@@ -894,6 +944,7 @@ class APIRouter(routing.Router):
894
944
  tags: Optional[List[Union[str, Enum]]] = None,
895
945
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
896
946
  openapi_extra: Optional[Dict[str, Any]] = None,
947
+ route_class: Optional[Type[APIRoute]] = None,
897
948
  ):
898
949
  return self.api_route(
899
950
  path,
@@ -901,6 +952,7 @@ class APIRouter(routing.Router):
901
952
  name=name,
902
953
  include_in_schema=include_in_schema,
903
954
  status_code=status_code,
955
+ middleware=middleware,
904
956
  deprecated=deprecated,
905
957
  request_class=request_class,
906
958
  response_model=response_model,
@@ -914,6 +966,7 @@ class APIRouter(routing.Router):
914
966
  generate_unique_id_function=generate_unique_id_function,
915
967
  openapi_extra=openapi_extra,
916
968
  tags=tags,
969
+ route_class=route_class,
917
970
  )
918
971
 
919
972
  def head(
@@ -923,6 +976,7 @@ class APIRouter(routing.Router):
923
976
  name: str = None,
924
977
  include_in_schema: bool = True,
925
978
  status_code: Optional[int] = None,
979
+ middleware: Sequence[Middleware] | None = None,
926
980
  deprecated: Optional[bool] = None,
927
981
  request_class: Type[Request] = Default(Request),
928
982
  response_model: Optional[Type[Any]] = None,
@@ -941,6 +995,7 @@ class APIRouter(routing.Router):
941
995
  tags: Optional[List[Union[str, Enum]]] = None,
942
996
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
943
997
  openapi_extra: Optional[Dict[str, Any]] = None,
998
+ route_class: Optional[Type[APIRoute]] = None,
944
999
  ):
945
1000
  return self.api_route(
946
1001
  path,
@@ -948,6 +1003,7 @@ class APIRouter(routing.Router):
948
1003
  name=name,
949
1004
  include_in_schema=include_in_schema,
950
1005
  status_code=status_code,
1006
+ middleware=middleware,
951
1007
  deprecated=deprecated,
952
1008
  request_class=request_class,
953
1009
  response_model=response_model,
@@ -961,6 +1017,7 @@ class APIRouter(routing.Router):
961
1017
  generate_unique_id_function=generate_unique_id_function,
962
1018
  openapi_extra=openapi_extra,
963
1019
  tags=tags,
1020
+ route_class=route_class,
964
1021
  )
965
1022
 
966
1023
  def patch(
@@ -970,6 +1027,7 @@ class APIRouter(routing.Router):
970
1027
  name: str = None,
971
1028
  include_in_schema: bool = True,
972
1029
  status_code: Optional[int] = None,
1030
+ middleware: Sequence[Middleware] | None = None,
973
1031
  deprecated: Optional[bool] = None,
974
1032
  request_class: Type[Request] = Default(Request),
975
1033
  response_model: Optional[Type[Any]] = None,
@@ -988,6 +1046,7 @@ class APIRouter(routing.Router):
988
1046
  tags: Optional[List[Union[str, Enum]]] = None,
989
1047
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
990
1048
  openapi_extra: Optional[Dict[str, Any]] = None,
1049
+ route_class: Optional[Type[APIRoute]] = None,
991
1050
  ):
992
1051
  return self.api_route(
993
1052
  path,
@@ -995,6 +1054,7 @@ class APIRouter(routing.Router):
995
1054
  name=name,
996
1055
  include_in_schema=include_in_schema,
997
1056
  status_code=status_code,
1057
+ middleware=middleware,
998
1058
  deprecated=deprecated,
999
1059
  request_class=request_class,
1000
1060
  response_model=response_model,
@@ -1008,6 +1068,7 @@ class APIRouter(routing.Router):
1008
1068
  generate_unique_id_function=generate_unique_id_function,
1009
1069
  openapi_extra=openapi_extra,
1010
1070
  tags=tags,
1071
+ route_class=route_class,
1011
1072
  )
1012
1073
 
1013
1074
  def trace(
@@ -1017,6 +1078,7 @@ class APIRouter(routing.Router):
1017
1078
  name: str = None,
1018
1079
  include_in_schema: bool = True,
1019
1080
  status_code: Optional[int] = None,
1081
+ middleware: Sequence[Middleware] | None = None,
1020
1082
  deprecated: Optional[bool] = None,
1021
1083
  request_class: Type[Request] = Default(Request),
1022
1084
  response_model: Optional[Type[Any]] = None,
@@ -1035,6 +1097,7 @@ class APIRouter(routing.Router):
1035
1097
  tags: Optional[List[Union[str, Enum]]] = None,
1036
1098
  # Will be deeply merged with the automatically generated OpenAPI schema for the path operation.
1037
1099
  openapi_extra: Optional[Dict[str, Any]] = None,
1100
+ route_class: Optional[Type[APIRoute]] = None,
1038
1101
  ):
1039
1102
  return self.api_route(
1040
1103
  path,
@@ -1042,6 +1105,7 @@ class APIRouter(routing.Router):
1042
1105
  name=name,
1043
1106
  include_in_schema=include_in_schema,
1044
1107
  status_code=status_code,
1108
+ middleware=middleware,
1045
1109
  deprecated=deprecated,
1046
1110
  request_class=request_class,
1047
1111
  response_model=response_model,
@@ -1055,4 +1119,5 @@ class APIRouter(routing.Router):
1055
1119
  generate_unique_id_function=generate_unique_id_function,
1056
1120
  openapi_extra=openapi_extra,
1057
1121
  tags=tags,
1122
+ route_class=route_class,
1058
1123
  )
starmallow/utils.py CHANGED
@@ -9,7 +9,7 @@ from contextlib import AsyncExitStack, asynccontextmanager, contextmanager
9
9
  from dataclasses import is_dataclass
10
10
  from decimal import Decimal
11
11
  from enum import Enum
12
- from types import NoneType
12
+ from types import NoneType, UnionType
13
13
  from typing import (
14
14
  TYPE_CHECKING,
15
15
  Any,
@@ -191,7 +191,7 @@ def is_body_allowed_for_status_code(status_code: int | str | None) -> bool:
191
191
 
192
192
 
193
193
  def is_optional(field):
194
- return get_origin(field) is Union and type(None) in get_args(field)
194
+ return get_origin(field) in (Union, UnionType) and type(None) in get_args(field)
195
195
 
196
196
 
197
197
  def get_path_param_names(path: str) -> Set[str]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: starmallow
3
- Version: 0.4.0
3
+ Version: 0.5.1
4
4
  Summary: StarMallow framework
5
5
  Project-URL: Homepage, https://github.com/mvanderlee/starmallow
6
6
  Author-email: Michiel Vanderlee <jmt.vanderlee@gmail.com>
@@ -1,10 +1,10 @@
1
- starmallow/__init__.py,sha256=fE4KZucjP-MqtKdZJkyPl8VpJdp0A1h_jNbSkHuJF8c,322
2
- starmallow/applications.py,sha256=7tRWNi-Vqsurb-bvQUuSeTVX0_9HIqSFzRdMwQUb7Sk,30810
1
+ starmallow/__init__.py,sha256=bazGj9TH8fId8pbGpljym-YfomnpPBSyM_RWlxhCitg,322
2
+ starmallow/applications.py,sha256=mSL4YDozP8n6v22g4NX7EAMXmGhzzhtjtZd68YHcFvw,31720
3
3
  starmallow/concurrency.py,sha256=MVRjo4Vqss_yqhaoeVt3xb7rLaSuAq_q9uYgTwbsojE,1375
4
4
  starmallow/constants.py,sha256=u0h8cJKhJY0oIZqzr7wpEZG2bPLrw5FroMnn3d8KBNQ,129
5
5
  starmallow/dataclasses.py,sha256=ap9DInvQjH2AyI4MAAnbDEuNnbPb94PigaNmEb7AQU8,2658
6
6
  starmallow/datastructures.py,sha256=iH_KJuJ6kBCWEsnHFLdA3iyb6ZxhfdMHYrJlhiEZtDU,839
7
- starmallow/decorators.py,sha256=7635d-JxCbEIqlAloekenGO2ucBSD16Q7zc4v6IQGPU,3773
7
+ starmallow/decorators.py,sha256=MYk3WEFRSfQTN0Y3JoL3Y_Cz47gatMrVEPtNDw42XwU,4105
8
8
  starmallow/delimited_field.py,sha256=gonWgYg6G5xH2yXAyfDgkePmQ8dUaRSp2hdJ3mCfOBw,3466
9
9
  starmallow/docs.py,sha256=eA39LunVMEoPU5ge4qxm2eiJbrFTUSUu5EhG1L_LKxk,6268
10
10
  starmallow/endpoint.py,sha256=YdEtRKF1Z-p_KXoqJJNP_9nEwOzvgxYoMI3Rly7ECrM,15888
@@ -12,15 +12,15 @@ starmallow/endpoints.py,sha256=UrwVZCxbmWI20iNtJ0oXxo4d3-y12TjsOGs_jnStTiU,939
12
12
  starmallow/exception_handlers.py,sha256=gr2qLYWEtsIEH28n7OreEiiLVz6Y7b6osRyS9esJbBk,891
13
13
  starmallow/exceptions.py,sha256=vabtPJkTmtCdC8_2OPBE8Osz0v0KxaSOX6IWf1jgNkc,872
14
14
  starmallow/fields.py,sha256=arrTabCYoJFZcoY69EZTBH3YUg7CUSr3-zYLiAjYLTM,1238
15
- starmallow/params.py,sha256=-f6ut1p_w_I8lyEgRciJxUtHmoVXKAD2Ug4KuRjPlJA,8661
15
+ starmallow/params.py,sha256=MJzUzUs6GEyrbpDZ1r8To8vR-QwpopdxDStq802o5Ug,8662
16
16
  starmallow/request_resolver.py,sha256=kT7B0BWSqBP_9Jl865Ya_Op9I3W4FyfBxXjvtucWT_0,10785
17
17
  starmallow/requests.py,sha256=o_yNhH9WJ35uAGuoXa5_gihevHeaveOvkP525dbwQSU,843
18
18
  starmallow/responses.py,sha256=k2pf_m21ykf_FECdODUz400pMucMJJf_Zm8TXFujvaU,2012
19
- starmallow/routing.py,sha256=8oXJb-3EixI3iYEY2q0r31x8NZnB56RKKIEfhtjjTpQ,42157
19
+ starmallow/routing.py,sha256=Uxnlkl4eIs56TZ8VAgNmlh-K89ku1Xu_ROR5S8x-rkg,45128
20
20
  starmallow/schema_generator.py,sha256=BKtXVQoNFWoAIEtiRNylWls_7nyFIshy3_myooogjoI,17806
21
21
  starmallow/serializers.py,sha256=rBEKMNgONgz_bai12uDvAEMCI_aEFGsqMSeIoWtlrOI,12514
22
22
  starmallow/types.py,sha256=8GXWjvzXQhF5NMHf14fbid6uErxVd1Xk_w2I4FoUgZ4,717
23
- starmallow/utils.py,sha256=AkVesTbYnshaXZqdgpc09TpZF07LIUeCOwOlvCaQrAI,11412
23
+ starmallow/utils.py,sha256=Ab6F2yOiy65gVGC2C4mNyKiPTPdsRyH5eVAv7Q_dGbw,11436
24
24
  starmallow/websockets.py,sha256=yIz3LzTBMNclpEoG7oTMbQwxbcdKNU6M8XcqZMyBTuA,2223
25
25
  starmallow/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  starmallow/ext/marshmallow/__init__.py,sha256=33jENGdfPq4-CDG0LOmN3KOGW1pXTy7a2oMwy4hrYzM,208
@@ -34,7 +34,7 @@ starmallow/security/http.py,sha256=cpGjM1kFDq3i_bOY96kMkf4cspBUxFkkET9lTK3NA-0,6
34
34
  starmallow/security/oauth2.py,sha256=1nv1580PY4cwgu5gzpQCf2MfMNv2Cfv05753AUHPOhQ,10005
35
35
  starmallow/security/open_id_connect_url.py,sha256=IPsL2YzWc2mPwJbrUn6oFRTi7uRAG6mR62CGwmzBs1k,1399
36
36
  starmallow/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293
37
- starmallow-0.4.0.dist-info/METADATA,sha256=jPVSz2HCZ8VpNCrkbR2ZPV_ia-WHWodk73LdQUF3jkU,5651
38
- starmallow-0.4.0.dist-info/WHEEL,sha256=y1bSCq4r5i4nMmpXeUJMqs3ipKvkZObrIXSvJHm1qCI,87
39
- starmallow-0.4.0.dist-info/licenses/LICENSE.md,sha256=QelyGgOzch8CXzy6HrYwHh7nmj0rlWkDA0YzmZ3CPaY,1084
40
- starmallow-0.4.0.dist-info/RECORD,,
37
+ starmallow-0.5.1.dist-info/METADATA,sha256=bg0HNEKMvq6nDZyRW8MOILAsTtXmOmzWwaFM2q2J3cE,5651
38
+ starmallow-0.5.1.dist-info/WHEEL,sha256=y1bSCq4r5i4nMmpXeUJMqs3ipKvkZObrIXSvJHm1qCI,87
39
+ starmallow-0.5.1.dist-info/licenses/LICENSE.md,sha256=QelyGgOzch8CXzy6HrYwHh7nmj0rlWkDA0YzmZ3CPaY,1084
40
+ starmallow-0.5.1.dist-info/RECORD,,