3 ms·
You can just define them as functions that are part of the class. Something like: @dataclass class AuthMethod: credentials: typing.Any cache: typing.Any
by curryst 6y ago
You can just define them as functions that are part of the class.
Something like:
@dataclass
class AuthMethod:
credentials: typing.Any
cache: typing.Any
apply_to_request: typing.Callable[[typing.Any, typing.Any, Request], None]
@dataclass
class AuthMapping:
method: AuthMethod
matches: typing.Callable[[str], bool]
class Client:
root_url: str
url_format: str
auth_methods: typing.List[AuthMethod]
def auth_request(client: Client, req: Request):
applies = filter(client.auth_methods, lambda x: x.matches(req))
if len(applies) > 1:
raise Exception("multiple auth methods found")
elif len(applies) == 1:
method = applies[0]
method.apply_to_request(method.credentials, method.cache, req)
Then you would statically define your service's auth methods by URL, so users can just do:
my_client = Client(auth_methods=MyServicesAuthMethods)
or you can create a helper function like:
def create_client_a(base_url: str):
return Client(base_url, auth_methods=[...])
Alternately I think you can use closures, but I'm not totally positive about the scoping.
AuthMethod = typing.Callable[[Request], None]
def auth_method_a(username, password) -> AuthMethod:
my_token = None
def __auth_method_a(req: Request):
if my_token is None:
my_token = do_login(username, password)
req.headers['token'] = my_token
return __auth_method
That creates a standard interface (a function that accepts a Request), without assuming anything about the underlying protocol.