Output#

Default Mode - The AttrDict and ListCollection#

By default, all schemas will produce AttrDict output objects, and all groups of objects created with a List field will produce ListCollection objects.

AttrDict#

The AttrDict object is a subclass of dict with two specialized features:

Attribute Access to Keys: You can use attribute access to get keys. So if you obtain a result, then result["name"] == result.name. This works as long as there is not an AttrDict method with the same name.

Data Conversion: You can easily convert the AttrDict to other similar types as:

  • AttrDict.to_dict - Converts to a simple Python dictionary.

  • AttrDict.to_mongo - Converts to a Mongo-compatible Python dictionary object (mostly by converting all datetime.date objects to datetime.datetime objects, since MongoDb doesn’t have a Date type).

  • AttrDict.to_pandas - Converts to a Pandas Series object.

ListCollection#

The ListCollection object is a subclass of list with several enhanced features:

Data Conversion: It supports similar data conversion features:

  • ListCollection.to_list - Converts to a simple Python list.

  • ListCollection.to_records - Converts to a simple Python list, with all members converted to simple Python dicts.

  • ListCollection.to_mongo - Converts to a simple python list, with all members converted to simple Python dicts compatible with MongoDB (casting datetime.dates as datetime.datetimes)

  • ListCollection.to_json - Converts to a JSON string

  • ListCollection.to_pandas - Converts to a DataFrame, with each object as a row

Data Munging / Mangling: You can also modify the data contained in the collection with the following methods:

  • ListCollection.explode

  • ListCollection.unpack

  • ListCollection.values

  • ListCollection.values_list

Model Mode - Dataclasses and Custom Models#

As an alternative, you can have your schemas return model classes, such as dataclass objects, or any other Python class that takes as its initializer a dictionary converted with ** notation. i.e. SomeClass(**dict). Model mode is activated by setting use_model = True in a Meta object on your top level Schema, like this:

class SomeSchema(Schema):
    class Meta:
        use_model = True

This will be passed down to all subschemas, so you only need to do it once. The model classes can be set in one of three ways:

Autogenerated Dataclasses#

If you set use_model = True and do nothing else, your schemas will create custom dataclass objects based on its fields, recursing to any subschemas. You can get the base dataclass object at SomeSchema.__model__ on an instance of the Schema.

Inferred Models#

The model class can be inferred from your package structure. If your file structure looks like this:

-package
 -schema.py <-- Schema is in this file
 -model.py <-- Model class is in this file

then the model can be inferred by stripping the name “Schema” out of the class name. For example:

# In schema.py
class ThingSchema(Schema):
   class Meta:
       use_model = True
   # ..
# In model.py
class Thing():
   # ..

In this case, the schema will find the Thing class and use it. This also works for more nested structures if you have lots of schemas and models, as long as the folder structures mirror each other. e.g.:

-package
 -schema
  -thing_schema.py
 -model
  -thing.py

The __model__ attribute#

If you provide a __model__ attribute on your schemas, then the .load function will use that model. The __model__ attribute can either be a Python Class (including a dataclass), or a string value.

If you set a string value, then the Schema will attempt to import a model at the provided path. For example:

# Same Module
class Thing():
    #...

class ThingSchema(Schema):
    class Meta:
        use_model = True
    __model__ = "Thing"

Or

# In the same Package, in a file called model.py
class Thing():
    #...

# In the same Package, in a file called schema.py
class ThingSchema(Schema):
    class Meta:
        use_model = True
    __model__ = ".model.Thing"

Or

# In a different package, called "model", in a file called "thing.py"
class Thing():
    #...

# In a different module
class ThingSchema(Schema):
    class Meta:
        use_model = True
    __model__ = "model.thing.Thing"