Faust integration
This library also has support to generate Avro Schemas from a faust.Record using AvroRecord.
AvroRecord is just a class that inherits from faust.Record and AvroModel respectively.
Note
All the AvroModel features like serialization, parsing objects, validation and fake, are available with AvroRecord
Example:
Basic usage
import typing
from faust.models import fields
from dataclasses_avroschema.faust import AvroRecord
class UserAdvance(AvroRecord):
name: str
age: int
pets: typing.List[str] = fields.StringField(required=False, default=["dog", "cat"])
accounts: typing.Dict[str, int] = fields.IntegerField(required=False, default={"key": 1})
has_car: bool = fields.BooleanField(required=False, default=False)
favorite_colors: typing.Tuple[str] = fields.StringField(required=False, default=("BLUE", "YELLOW", "GREEN"))
country: str = fields.StringField(required=False, default="Argentina")
address: typing.Optional[str] = None
class Meta:
schema_doc = False
UserAdvance.avro_schema()
resulting in
{
"type": "record",
"name": "UserAdvance",
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "age",
"type": "long"
},
{
"name": "pets",
"type": {
"type": "array",
"items": "string",
"name": "pet"
},
"default": ["dog", "cat"]
},
{
"name": "accounts",
"type": {
"type": "map",
"values": "long",
"name": "account"
},
"default": {"key": 1}
},
{
"name": "has_car",
"type": "boolean",
"default": false
},
{
"name": "favorite_colors",
"type": {
"type": "array", "items": "string", "name": "favorite_color",
"default": ["BLUE", "YELLOW", "GREEN"]
}
},
{
"name": "country",
"type": "string",
"default": "Argentina"
},
{
"name": "address",
"type": ["null", "string"],
"default": null
}
]
}
(This script is complete, it should run "as is")
Data validation
For models there is no validation of data by default in Faust, however there is an option that will enable validation for all common JSON fields (int, float, str, etc.), and some commonly used Python ones (datetime, Decimal, etc.)
In order to validate the data validation=True must be used as is described in tha faust documenation
Data validation
import typing
from faust.models import fields
from dataclasses_avroschema.faust import AvroRecord
class UserAdvance(AvroRecord, validation=True):
name: str
age: int
pets: typing.List[str] = fields.StringField(required=False, default=['dog', 'cat'])
accounts: typing.Dict[str, int] = fields.IntegerField(required=False, default={"key": 1})
has_car: bool = fields.BooleanField(required=False, default=False)
favorite_colors: typing.Tuple[str] = fields.StringField(required=False, default=("BLUE", "YELLOW", "GREEN"))
country: str = fields.StringField(required=False, default="Argentina")
address: typing.Optional[str] = None
class Meta:
schema_doc = False
UserAdvance(name="marcos", age="bond")
ValueError: invalid literal for int() with base 10: 'bond'
import typing
from dataclasses_avroschema.faust import AvroRecord
class UserAdvance(AvroRecord):
name: str
age: int
pets: typing.List[str] = fields.StringField(required=False, default=['dog', 'cat'])
accounts: typing.Dict[str, int] = fields.IntegerField(required=False, default={"key": 1})
has_car: bool = fields.BooleanField(required=False, default=False)
favorite_colors: typing.Tuple[str] = fields.StringField(required=False, default=("BLUE", "YELLOW", "GREEN"))
country: str = fields.StringField(required=False, default="Argentina")
address: typing.Optional[str] = None
class Meta:
schema_doc = False
UserAdvance(name="marcos", age="juan") # WRONG data
(This script is complete, it should run "as is")
Faust and dataclasses_avroschema batteries
To dict, to json and serialization
import typing
from faust.models import fields
from dataclasses_avroschema.faust import AvroRecord
class Address(AvroRecord):
street: str
street_number: int
class UserAdvance(AvroRecord):
name: str
age: int
address: Address
pets: typing.List[str] = fields.StringField(required=False, default=['dog', 'cat'])
accounts: typing.Dict[str, int] = fields.IntegerField(required=False, default={"key": 1})
has_car: bool = fields.BooleanField(required=False, default=False)
favorite_colors: typing.Tuple[str] = fields.StringField(required=False, default=("BLUE", "YELLOW", "GREEN"))
country: str = fields.StringField(required=False, default="Argentina")
class Meta:
schema_doc = False
user = UserAdvance(
name="bond",
age=50,
address=Address(
street="Wilhelminastraat",
street_number=29,
)
)
assert user.to_dict() == {
'name': 'bond', 'age': 50,
'address': {
'street': 'Wilhelminastraat',
'street_number': 29
},
'pets': ['dog', 'cat'],
'accounts': {'key': 1},
'has_car': False,
'favorite_colors': ('BLUE', 'YELLOW', 'GREEN'),
'country': 'Argentina'
}
assert user.to_json(separators=(",",":",)) == """{"name":"bond","age":50,"address":{"street":"Wilhelminastraat","street_number":29},"pets":["dog","cat"],"accounts":{"key":1},"has_car":false,"favorite_colors":["BLUE","YELLOW","GREEN"],"country":"Argentina"}"""
event = user.serialize()
assert event == b'\x08bondd Wilhelminastraat:\x04\x06dog\x06cat\x00\x02\x06key\x02\x00\x00\x06\x08BLUE\x0cYELLOW\nGREEN\x00\x12Argentina'
assert UserAdvance.deserialize(data=event) == UserAdvance(name='bond', age=50, address=Address(street='Wilhelminastraat', street_number=29), pets=['dog', 'cat'], accounts={'key': 1}, has_car=False, favorite_colors=('BLUE', 'YELLOW', 'GREEN'), country='Argentina')