Package: data-polyglot
data_polyglotThe goal of this project is to create a set of tools to help write API tests faster.List of tools:JSON SerializerTable DataLocal StorageJSON SerializerCreate models for payload and response with fewer lines of code then alternative packages.
Leverage the power of autocomplete to access variables.
C# does it with Newtonsoft, it's time we get a similar convenient way of serialization.class SomeData(Serializable):
    name: str = serialize('name')
    item_id: int = serialize('id')

payload = SomeData()
payload.name = 'some item name'
payload.item_id = 123

data = payload.to_json()
# data would be { 'name': 'some item name', 'id': 123 }

response = requests.get('https://example.com/items')
response_data = SomeData.from_json(response.json())Note the use of type hinting.serialize(key_name, required, default_value, custom_converter) for to_json()key_name: Key in a dictionary when creating payload (JSON attribute).required: Set False will not add field to the payload if value is None.
Set True will add None field as null.default_value: If value was not assigned to the class variable use this default value.custom_converter: A function to convert class variable to another type,
likedatetimeinto string.Example of custom_converter:# Assign datetime to a class variable 'date'. It will be converted to a string.
date = serialize('date', custom_converter=lambda date: date.strftime('%Y-%m-%d'))serialize(key_name, required, default_value, custom_converter) for from_json()key_name: JSON attribute to parse from the dictionary.required: Set False will not raise an error if field is missing in response, but will assign None
Set True will rase an error if field is missing in response.default_value: If field is missing in response assign specified default value (require flag ignored)custom_converter: A function to convert variable to another type,
for example, string to datetime.Example of custom_converter:# Assuming the datetime sting has a pattern '%Y-%m-%d', parse the field and convert to datetime.
date: datetime = serialize('date', custom_converter=lambda date: datetime.strptime(date, '%Y-%m-%d'))NOTE!from_jsoncan process alistand return a list of serialized object,
BUT it doesn't hint that it's a list. Either do type hinting on returned value,
or process list yourself.# process list without type hinting
expected_list = [ResponseExampleModel.from_json(j_obj) for j_obj in response.json()]

# process list with type hinting
expected_list: List[ResponseExampleModel] = ResponseExampleModel.from_json(response.json())Nested classesIt's very common to nest JSON objects inside the payload or the response. Here's how to do it:# Create an object that would be nested following instructions provided above.
class NestedObject(Serializable):
    argument1: str = serialize('arg1')

class Payload(Serializable):
    nested_obj = NestedObject.nest('nested object')This structure will correspond with the following schema:{
    "nested object": {
        "arg1": "string"
    }
}If nested object is expected to be of typelist, then it's crucial to specify type hint:class Payload(Serializable):
    nested_obj: List[NestedObject] = NestedObject.nest('nested object')Usingto_jsonwhen.nest('key_name', required=True)raise error if class is None.Usingto_jsonwhen.nest('key_name', required=False)set json property to null if class is None.Usingfrom_jsonwhen.nest('key_name', required=True)raise error when did not find the field.Usingfrom_jsonwhen.nest('key_name', required=False)set class variable to None if did not find the field.to_json_text()Usesto_jsonmethod to create json structure and then turn it into a string.
Valuable when you have a payload that expects part of the json to be nested inside the string of a JSON property.Error ReportingWe want to write as few models as possible, so when we see the similarities between responses we would
instinctively want to share one model between them. As feature development goes on we may see changes
in responses that leads to breaking change in our automation framework.
When this happens an error message will show exactly what and where a property broke.Errors incustom_converterwill also raise a meaningful exception.TableData classA wrapper around API response for the table content to be rendered on the front-end.
Includes common table operations such as 'filter records by column name',
'get column value by row index'.
Your response would look something like this:{
    "page": 0,
    "per_page": 50,
    "table": [
        {"name": "item1", "price": 1.99, "quantity": 10 },
        {"name": "item2", "price": 2.99, "quantity": 5 },
        {"name": "item3", "price": 3.99, "quantity": 7 },
    ]
}In this case just pass down the table into the class during instantiation:table = TableData(response.json()['table'])You can also useTableDataclass in conjunction withSerializable class.
The example bellow demonstrates how to do that with the response example above:class TableResponseModel(Serializable):
    page: int = Serializable.serialize('page')
    per_page: int = Serializable.serialize('per_page')
    table: TableData = Serializable.serialize('table', custom_converter=lambda j_arr: TableData(j_arr))Example how to use table data:table = TableData(response.json()['table'])
table = table.filter_by_column_name('type', 'food')
value = table.get_column_value_by_row_index(0, 'name')You can also extendTableDataclass and create methods to wrap column name,
so you don't have to hardcode strings in your tests.Local StorageStore your test data locally in a JSON file usingLocalStorageclass.
Useful when connecting data seeding scripts with test running scripts.
Create, read, update and delete data as if it was an external microservice, providing path to data as an endpoint.
In case the project ever grows to have the need for an external microservice to store test data -
it would be a fast transition.To start:Initialize local storage by providing the file path. If file doesn't exist, new file will be created.Save simple data types, dictionaries, and lists usingcreatemethod.Read data in the specified path usingreadmethod.Example:file_path = os.path.dirname(os.path.abspath(__file__))

storage = LocalStorage(file_path)
storage.create('/inventory/item_1/name', 'Do not delete!')
item_name = storage.read('/inventory/item_1/name')

storage.update('/inventory/item_1/name', 'Do not delete 1!')
exists = storage.is_key_present('/inventory/item_1/name')
storage.delete('/inventory/item_1/name')