11from __future__ import annotations
22
33from abc import ABC , abstractmethod
4+ from collections import ChainMap
45from dataclasses import dataclass
5- from typing import ClassVar , Generic , Sequence , Type , TypeVar
6+ from functools import wraps
7+ from typing import (
8+ Any ,
9+ ClassVar ,
10+ Dict ,
11+ Generic ,
12+ Mapping ,
13+ Sequence ,
14+ Type ,
15+ TypeVar ,
16+ cast ,
17+ )
618
19+ from pydantic import BaseModel , create_model
720from pydantic .generics import GenericModel
821from pydantic .types import conint
922
@@ -23,6 +36,19 @@ def to_raw_params(self) -> RawParams:
2336 pass # pragma: no cover
2437
2538
39+ def _create_params (cls : Type [AbstractParams ], fields : Dict [str , Any ]) -> Mapping [str , Any ]:
40+ if not issubclass (cls , BaseModel ):
41+ raise ValueError (f"{ cls .__name__ } must be subclass of BaseModel" )
42+
43+ incorrect = sorted (fields .keys () - cls .__fields__ .keys ())
44+ if incorrect :
45+ ending = "s" if len (incorrect ) > 1 else ""
46+ raise ValueError (f"Unknown field{ ending } { ', ' .join (incorrect )} " )
47+
48+ anns = ChainMap (* (obj .__dict__ .get ("__annotations__" , {}) for obj in cls .mro ()))
49+ return {name : (anns [name ], val ) for name , val in fields .items ()}
50+
51+
2652class AbstractPage (GenericModel , Generic [T ], ABC ):
2753 __params_type__ : ClassVar [Type [AbstractParams ]]
2854
@@ -31,6 +57,22 @@ class AbstractPage(GenericModel, Generic[T], ABC):
3157 def create (cls : Type [C ], items : Sequence [T ], total : int , params : AbstractParams ) -> C :
3258 pass # pragma: no cover
3359
60+ @classmethod
61+ def with_custom_options (cls : C , ** kwargs : Any ) -> C :
62+ params_cls = cast (Type [AbstractPage ], cls ).__params_type__
63+
64+ custom_params : Any = create_model (
65+ params_cls .__name__ ,
66+ __base__ = params_cls ,
67+ ** _create_params (params_cls , kwargs ),
68+ )
69+
70+ @wraps (cls , updated = ()) # type: ignore
71+ class CustomPage (cls [T ], Generic [T ]): # type: ignore
72+ __params_type__ : ClassVar [Type [AbstractParams ]] = custom_params
73+
74+ return cast (C , CustomPage )
75+
3476 class Config :
3577 arbitrary_types_allowed = True
3678
0 commit comments