Models#
APIModel is inspired by pydantic and based on annotations. If you have used pydantic before this library should be seem familiar to you.
Models are defined by inheriting from apimodel.APIModel.
Basic usage#
We define a model with two fields. An integer id and an optional string name.
import apimodel
class User(apimodel.APIModel):
id: int
name: str = "Anonymous"
user = User(id="123")
print(user)
# User(id=123, name='Anonymous')
user.id has been casted to an integer and user.name has the default value.
print(user.as_dict())
# {'id': 123, 'name': 'Anonymous'}
Model Nesting#
Models can be nested
class Item(apimodel.APIModel):
name: str
class Storage(apimodel.APIModel):
max_size: int = 256
items: list[Item]
class User(apimodel.APIModel):
id: int
storage: Storage
user = User(id="123", storage={"items": [{"name": "foo"}, {"name": "bar"}]})
print(user)
# User(id=123, storage=Storage(items=[Item(name='foo'), Item(name='bar')], max_size=256))
print(user.storage.items[0].name)
# foo
Fields#
Metadata can be added to fields through apimodel.fields.FieldInfo at runtime.
The first positional argument is always the default value. ... denotes a required value.
See apimodel.FieldInfo for details.
import datetime
import apimodel
class Item(apimodel.APIModel):
id: int = apimodel.Field(..., private=True)
created_at: datetime.datetime = apimodel.Field(..., name="createdAt")
available: bool = apimodel.Field(False)
item = Item({"id": "42", "name": "foo", "createdAt": 1577836800})
print(item.as_dict())
# {'created_at': datetime.datetime(2020, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), 'available': False}
print(item.id)
# 42
Extras#
Some values may require to be shared across all nested models. For example your API client. This can be done with inheritance and apimodel.Extra.
Extra values do not appear in model.as_dict()
class Client:
def __init__(self, token: str) -> None:
self.token = token
def fetch_user(self, id: int) -> User:
data = self._request_endpoint("GET", f"/users/{id}")
return User(data, client=self)
def edit_user(self, user_id: int, **kwargs: object) -> None:
...
def buy_item(self, item_id: int) -> None:
...
...
class BaseModel(apimodel.APIModel):
# underscore gets stripped at runtime
_client: Client = apimodel.Extra()
class Item(BaseModel):
id: int
name: str
def buy(self) -> None:
self.client.buy_item(self.id)
class User(BaseModel):
id: int
name: str
items: list[Item]
def edit(self, **kwargs: object) -> None:
self.client.edit_user(self.id, **kwargs)
client = Client("token")
user = client.fetch_user(42)
print(user)
# User(id=1, name='John', items=[Item(id=42, name='foo'), Item(id=43, name='bar')])
user.edit(name="John Doe")
user.items[1].buy()
Debugging#
APIModel can be used with python-devtools developed by the author of pydantic.