SRserves85 / avro-to-python

Light tool for compiling avro schema files (.avsc) to python classes
MIT License
25 stars 19 forks source link

Map of array not well handled #40

Closed fmiguelez closed 3 months ago

fmiguelez commented 4 months ago

If we rewrite RecordWithMap.avsc to include a map with array of primitives like the following:

{
    "type": "record",
    "name": "RecordWithMap",
    "namespace": "records",
    "fields": [
        {
            "name": "thingMap",
            "type": {
                "type": "map",
                "values": {
                    "type": "record",
                    "name": "Thing",
                    "fields": [
                        {
                            "name": "id",
                            "type": "int"
                        }
                    ]
                }
            }
        },
        {
            "name": "intMap",
            "type": {
                "type": "map",
                "values": "int"
            }
        },
        {
            "name": "thingMap2",
            "type": {
                "type": "map",
                "values": "Thing"
            }
        },
        {
            "name": "thingMap3",
            "type": {
                "type": "map",
                "values": "record.Thing"
            }
        },
        {
            "name": "arrayMap",
            "type": {
                "type": "map",
                "values": {
                    "type": "array",
                    "items": "string"
                }
            }
        }
    ]
}

And adapt the test

    def test_map_record(self):
        """ tests that nested things have correct mappings and namespaces """

        from records import RecordWithMap
        from records import Thing

        data1 = {'thingMap': {'string1': {'id': 10},
                              'string2': Thing({'id': 10})},
                 'intMap': {'lksdfl': 23},
                 'thingMap2': {'string1': {'id': 10},
                               'string2': Thing({'id': 10})},
                 'thingMap3': {'string1': {'id': 10},
                               'string2': Thing({'id': 10})},
                 'arrayMap': {'string1': ['value1', 'value2']}
                 }
        data2 = {'thingMap': {'string1': {'id': 10},
                              'string2': Thing({'id': 10})},
                 'intMap': {'lksdfl': 'NOT A STRING'}}
        data3 = {'thingMap': [{'string1': {'id': 10}},
                              {'string2': Thing({'id': 10})}],
                 'intMap': [{'lksdfl': 23}]}

        record1 = RecordWithMap(data1)
        record2 = RecordWithMap(record1)

        with self.assertRaises(TypeError):
            RecordWithMap(data2)

        with self.assertRaises(TypeError):
            RecordWithMap(data3)

        self.assertEqual(
            record1.serialize(),
            record2.serialize()
        )

It will fail with following error (invalid generated code):

>   from records.RecordWithMap import RecordWithMap
E     File "O:\ws\mdp\avro-to-python\tests\avsc\records\records\RecordWithMap.py", line 193
E       self.arrayMap[key] = sub_array
E       ^^^^
E   IndentationError: expected an indented block after 'for' statement on line 192

Malformed code:

    def set_arrayOfUnionMap(self, values: dict) -> None:
        self.arrayOfUnionMap = {}
        if isinstance(values, dict):
            for key, value in values.items():
                if not isinstance(key, str):
                    raise TypeError(
                        f"Key '{key}' for 'arrayOfUnionMap' should be string but was: {type(key)}"
                    )
                sub_array = []
                if isinstance(value, list):
                    for element in value:                   // <<<<<<< Loop without content
                    self.arrayOfUnionMap[key] = sub_array   
                else:
                    raise TypeError(f"Type for entry '{key}' of field 'arrayOfUnionMap' should be type list but was: {type(value)}")
        else:
            raise TypeError(f"Field 'arrayOfUnionMap' should be type dict but was: {type(values)}")