Module xmodel.json

The purpose of the JsonModel is to be able to create model classes from json data we have retrieved from somewhere that is not an API endpoint or as a subclass of data from an API endpoint that does not have it's own endpoint. We also want to be able to find any related models that may have an API endpoint that we can retrieve their data from. An example of this would be a database that has a RemoteModel's id stored within it that we may want to retrieve at a later date or only at certain times when that data is relevant so that we do not manually have to look up that RemoteModel ourselves and will let the associated model look itself up in the way that it knows how to.

Expand source code
"""
The purpose of the JsonModel is to be able to create model classes from json data we have
retrieved from somewhere that is not an API endpoint or as a subclass of data from an API
endpoint that does not have it's own endpoint. We also want to be able to find any related models
that may have an API endpoint that we can retrieve their data from. An example of this would be a
database that has a RemoteModel's id stored within it that we may want to retrieve at a later date
or only at certain times when that data is relevant so that we do not manually have to look up
that RemoteModel ourselves and will let the associated model look itself up in the way that it
knows how to.
"""

from typing import TypeVar
from .base import BaseModel


M = TypeVar('M')


class JsonModel(BaseModel):
    pass

Classes

class JsonModel (*args, **initial_values)

Used as the abstract base-class for classes/object that communicate with our REST API.

This is one of the main classes, and it's highly recommend you read the SDK Library Overview first, if you have not already. That document has many basic examples of using this class along with other related classes.

Attributes that start with _ or don't have a type-hint are not considered fields on the object that automatically get mapped to/from the JSON that is passed in. For more details see Type Hints.

When you sub-class BaseModel, you can create your own Model class, with your own fields/attrs. You can pass class arguments/paramters in when you declare your sub-class. The Model-subclass can provide parameters to the super class during class construction.

In the example below, notice the base_url part. That's a class argument, that is used by the super-class during the construction of the sub-class (before any instances are created). In this case it takes this and stores it on xmodel.rest.RestStructure.base_model_url as part of the structure information for the BaseModel subclass.

See Basic Model Example for an example of what class arguments are or look at this example below using a RestModel:

>>> # 'base_url' part is a class argument:
>>> from xmodel.rest import RestModel
>>> class Account(RestModel["Account"], base_url='/account'):
>>>    id: str
>>>    name: str

These class arguments are sent to a special method BaseStructure.configure_for_model_type(). See that methods docs for a list of avaliable class-arguments.

See BaseModel.__init_subclass__ for more on the internal details of how this works exactly.

Note: In the case of base_url example above, it's the base-url-endpoint for the model.

If you want to know more about that see xmodel.rest.RestClient.url_for_endpoint. It has details on how the final request Url is constructed.

This class also allows you to more easily with with JSON data via:

Other important related classes are listed below.

  • BaseApi Accessable via BaseModel.api.
  • xmodel.rest.RestClient: Accessable via xmodel.base.api.BaseApi.client.
  • xmodel.rest.settings.RestSettings: Accessable via xmodel.base.api.BaseApi.settings.
  • BaseStructure: Accessable via BaseApi.structure
  • xmodel.base.auth.BaseAuth: Accessable via xmodel.base.api.BaseApi.auth

Tip: For all of the above, you can change what class is allocated for each one

by changing the type-hint on a subclass.

Creates a new model object. The first/second params need to be passed as positional arguments. The rest must be sent as key-word arguments. Everything is optional.

Args

id
Specify the BaseModel.id attribute, if you know it. If left as Default, nothing will be set on it. It could be set to something via args[0] (ie: a JSON dict). If you do provide a value, it be set last after everything else has been set.
*args

I don't want to take names from what you could put into 'initial_values', so I keep it as position-only *args. Once Python 3.8 comes out, we can use a new feature where you can specify some arguments as positional-only and not keyword-able.

FirstArg - If Dict:

If raw dictionary parsed from JSON string. It just calls self.api.update_from_json(args[0]) for you.

FirstArt - If BaseModel:

If a BaseModel, will copy fields over that have the same name. You can use this to duplicate a Model object, if you want to copy it. Or can be used to copy fields from one model type into another, on fields that are the same name.

Will ignore fields that are present on one but not the other. Only copy fields that are on both models types.

**initial_values
Let's you specify other attribute values for convenience. They will be set into the object the same way you would normally doing it: ie: model_obj.some_attr = v is the same as ModelClass(some_attr=v).
Expand source code
class JsonModel(BaseModel):
    pass

Ancestors

Class variables

var apiBaseApi[BaseModel]

Inherited from: BaseModel.api

Used to access the api class, which is used to retrieve/send objects to/from api …

Static methods

def __init_subclass__(*, lazy_loader: Callable[[Type[~M]], None] = None, **kwargs)

Inherited from: BaseModel.__init_subclass__

We take all arguments (except lazy_loader) passed into here and send them to the method on our structure: …