Skip to content

Data Models

nanopie provides a Model class which you can inherit from to model data in their microservices and API backends. Each Model may include a number of Fields as attributes, which describe the data. With the help of Python metaclasses (PEP 3115), nanopie automatically adds to data model classes initializers and properties corresponding to the Fields you provide; you may then use instances of your data model classes in the same way as regular data classes.

from nanopie import Model, StringField, IntField

class User(Model):
    name = StringField()
    age = IntField()

user = User(name="Albert Wesker", age=49)
# Returns "Albert Wesker"
print(user.name)
# Returns 49
print(user.age)

In addition, you may specify a number of hints and constraints with each Field; nanopie can validate data against them automatically for you. The snippet below, for example, specifies a StringField whose value must have only alphabetic characters with a length of no less than 1 character and no more than 20 characters.

from nanopie import Model

class User(Model):
    name = StringField(max_length=20, min_length=1, pattern="^[a-zA-Z]$")

# These statements will raise an exception
user = User(name="#wesker")
user = User(name="")
user = User(name="SuperUltraMegaLongName")

user = User(name="Wesker")
# This will also raise an exception
user.name = ""

Fields

nanopie provides the following fields:

  • StringField: A field for string (str) typed data.
  • IntField: A field for integer (int) typed data.
  • FloatField: A field for float (float) typed data.
  • BoolField: A field for boolean (bool) typed data.
  • ArrayField: A field for array (List) typed data.
  • ObjectField: A field for object typed data. This field allows you to nest a data model within another data model.

StringField

To add a field for string typed data in your data model, specify a StringField as attribute in your Model class. This field supports the following hints and constraints:

Hint/Constraint Description
format The format of this field. For example, a StringField for timstamps may have its format set to date-time. This field is informational, i.e. nanopie will not be able to validate if the value of a StringField matches its format.
max_length The maximum length of this field, e.g. 20.
min_length The minimum length of this field, e.g. 1.
pattern The pattern of this field, in the form of a regular expression. A StringField, for example, with a pattern of ^[a-z]*$ will only accept strings with lower case alphabetic characters.
required Defaults to False; if set to True, this field is required in a model, i.e. its value cannot be None (an empty string, "", however is still valid).
default The default value of this field.
description The description of this field.
class UserCredential(Model):
    password = StringField(format="password",
                           max_length=16,
                           min_length=8,
                           pattern='[a-zA-Z0-9]^$',
                           required=True,
                           default='00000000',
                           description='An example StringField')

IntField

To add a field for integer typed data in your data model, specify an IntField as attribute in your Model class. This field supports the following hints and constraints:

Hint/Constraint Description
maximum The maximum value of this field.
exclusive_maximum Defaults to False; if set to True, the maximum value itself will be excluded. For example, if an IntField has maximum set to 20 and exclusive_maximum to True, 20 itself will not be a valid value for this field and the largest value this field can take will be 19 (< instead of <=).
minimum The minimum value of this field.
exclusive_minimum Defaults to False; if set to True, the minimum value itself will be excluded. For example, if an IntField has minimum set to 1 and exclusive_maximum to True, 1 itself will not be a valid value for this field and the smallest value this field can take will be 2 (> instead of >=).
required Defaults to False; if set to True, this field is required in a model, i.e. its value cannot be None.
default The default value of this field.
description The description of this field.
class User(Model):
    age = IntField(maximum=150,
                   exclusive_maximum=False,
                   minimum=0,
                   exclusive_minimum=False,
                   default=0,
                   required=True,
                   description="An example IntField")

FloatField

To add a field for float typed data in your data model, specify an FolatField as attribute in your Model class. This field supports the following hints and constraints:

Hint/Constraint Description
maximum The maximum value of this field.
exclusive_maximum Defaults to False; if set to True, the maximum value itself will be excluded. For example, if a FloattField has maximum set to 20.0 and exclusive_maximum to True, 20.0 itself will not be a valid value for this field (< instead of <=).
minimum The minimum value of this field.
exclusive_minimum Defaults to False; if set to True, the minimum value itself will be excluded. For example, if a FloatField has minimum set to 1.0 and exclusive_maximum to True, 1.0 itself will not be a valid value for this field (> instead of >=).
required Defaults to False; if set to True, this field is required in a model, i.e. its value cannot be None.
default The default value of this field.
description The description of this field.
class NewTempatureReadingEvent(Model):
    temperature = FloatField(maximum=100.0,
                             exclusive_maximum=False,
                             minimum=0.0,
                             exclusive_minimum=False,
                             default=0.0,
                             required=True,
                             description="An example FloatField")

BoolField

To add a field for boolean typed data in your data model, specify a BoolField as attribute in your Model class. This field supports the following hints and constraints:

Hint/Constraint Description
required Defaults to False; if set to True, this field is required in a model, i.e. its value cannot be None.
default The default value of this field.
description The description of this field.
class User(Model):
    is_subscriber = BoolField(required=True,
                              default=False,
                              description="An example BoolField")

ArrayField

To add a field for array (list) typed data in your data model, specify an ArrayField as attribute in your Model class. You must specify the type of the items of the array in the form of a Field along with the ArrayField itself. The code snippet below includes an ArrayField that accepts an array (list) of integers:

class Order(Model):
    item_ids = ArrayField(
        item_field=IntField(required=True)
    )

Note

nanopie will use the hints and constraints specified in the item field (if any) to validate each item in the array.

ArrayField supports the following hints and constraints:

Hint/Constraint Description
item_field Required. A field that describes the items in the array (list).
min_items The minimum number of items in the array.
max_items The maximum number of items in the array.
required Defaults to False; if set to True, this field is required in a model, i.e. its value cannot be None.
default The default value of this field.
description The description of this field.

ObjectField

ObjectField allows you to specify object typed data in your data model. It effectively nests a data model within another. Each ObjectField requires a Model class as argument, which describes what the object typed data looks like. The code snippet below includes an ObjectField that uses the Address data model and accepts an instance of the Address model as value:

class Address(Model):
    address_line_1 = StringField()
    address_line_2 = StringField()
    city = StringField()
    state_or_province = StringField()
    country_or_region = StringField()

class User(Model):
    name = StringField()
    address = ObjectField(model=Address)

user = User(
    name = "Albert Wesker",
    address = Address(address_line_1="Captain's office, STARS, Racoon City Police Dept.",
                      city="Racoon City",
                      state_or_province="MI",
                      country="US")
)

# Returns "Captain's office, STARS, Racoon City Police Dept."
print(user.address.address_line_1)

ObjectField supports the following hints and constraints:

Hint/Constraint Description
model Required. A data model that describes the object.
required Defaults to False; if set to True, this field is required in a model, i.e. its value cannot be None.
default The default value of this field.
description The description of this field.

Using Models

When you define a Model with a number of Fields, nanopie sets up these Fields as properties with getters and setters; it also configures an initializer for the Model class.

You can instantiate a Model using its initializer by passing the values of fields as keyword arguments. The initializer will validate these values against the hints and constraints in their fields. Fields that are not listed in the given keyword arguments will be assigned its default value (if specified) or None. Note that if a field is required but assigned the value of None, an exception will be thrown.

If you would like to skip the validation process, set the argument skip_validation to True when calling the initializer:

from nanopie import Model, StringField

class User(Model):
    name = StringField(required=True)

# An exception will be raised, as the required field, `name`, is not assigned
# a value
user = User()

# No exception will be raised
user = User(skip_validation=True)
# Returns None
print(user.name)

Once instantiated, you may update the values of fields with getters and setters. Note that when you assigned a value to a field, nanopie will automatically validate the input against the hints and constraints (if any) specified in the corresponding field.

The Model class also features some utility methods you can use, including

Method Type Description
from_dikt Class method Parses a Dict into a data model instance
to_dikt Instance method Dumps a data model instance into a Dict.
validate Instance method Validates the data model instance against its data model.
validate_instance Class method Validates any data model instance against the data model.

Exceptions

When a validation fails, nanopie will throw exceptions of the following classes; you may catch them and process the validation exceptions properly. All of the classes below inherit from the nanopie.misc.errors.ValidationError class (which is in turn based on the nanopie.misc.errors.ServiceError class).

Exception Description Field-specific Exception
ModelTypeNotMatchedError This exception is raised when the input data is of a data model different from the one used for validation. No
RequiredFieldMissingError This exception is raised when a missing field is missing (not assigned a value or assigned the value of None). Yes
FieldTypeNotMatchedError This exception is raised when a field is assigned a value not matching its associated data type. Yes
ListItemTypeNotMatchedError This exception is raised when an ArrayField is assigned a list in which one or more items does not match the field's associated item data type. Yes
StringMaxLengthExceededError This exception is raised when a StringField is assigned a value that is too long. Yes
StringMinLengthBelowError This exception is raised when a StringField is assigned a value that is too short. Yes
StringPatternNotMatchedError This exception is raised when a StringField is assigned a value that is not of the specified pattern. Yes
NumberMaxExceededError This exception is raised when an IntField or a FloatField is assigned a value that is too large. Yes
NumberMinBelowError This exception is raised when an IntField or a FloatField is assigned a value that is too small. Yes
ListTooManyItemsError This exception is raised when an ArrayField is assigned a list that has too many items. Yes
ListTooLittleItemsError This exception is raised when an ArrayField is assigned a list that has too little items. Yes

Each exception has 4 attributes:

  • source: The source data field or model.
  • data: The value assigned to the field or model that triggers the exception.
  • message: The error message.
  • response: The RPC response associated with the exception. Defaults to None.

If the exception is field specific, it will also include the name of the field in the data model, assigned_field_name, as an attribute.

Note

Learn more about nanopie exceptions in Exceptions.