I am creating a framework built on pydantic.BaseModel
that will manage the putting and getting of records from dynamodb.
An example of a model is as follows:
class User(DynamoDanticBaseModel):
user_id: str
first_name: str
@classmethod
def primary_key(cls) -> str:
return "USER#{user_id}"
@classmethod
def sort_key(cls) -> str:
return "USER"
Using __init_subclass__
, I can fetch the formatable strings and validate that the required parts of the PK/SK are defined on the class.
Defined generically is a classmethod get
that uses these values to call boto3 underneath and fetch the a record, fill in the model and return the new model instance.
user = User(user_id='example', first_name='Bacon')
user.put(dynamo_table_ref)
user = User.get(dynamo_table_ref, user_id='example')
user.first_name # => "Bacon"
This all works. My issue is that the get methods interface is: def get(cls, table, **kwargs):
. A developer cannot see what params are needed.
Is there a way to layout my code, or a pattern I should use, that would mean that I could have the signature hint show the required parameters? Dynamic to the required parameters defined in the primary key and sort key method?
e.g. def get(cls, table, user_id: str):
Unfortunately, no. It's not possible to define a parameter based on a dynamic string (or a Literal['foo']
/LiteralString
, for that matter).
The best you can do is to copy the generated __init__
's signature over, but you can't change their requiredness.
The second best solution is to write a Mypy plugin. This, of course, won't work with any other type checkers, including Pyright/Pylance.