schematics icon indicating copy to clipboard operation
schematics copied to clipboard

UnionType with ModelType fails during Model.to_primitive() with AttributeError: 'Context' object has no attribute 'convert'

Open acormier128 opened this issue 7 years ago • 0 comments

Attempting to use ModelType as a type within a UnionType seems to work except when trying to convert the model back into a dict via to_primitive():

The test:

import pytest
from schematics import models, types, undefined

class SimpleModel(models.Model):
    simple_field = types.StringType()

class MyModel(models.Model):
    my_field = types.UnionType((types.StringType, types.ModelType), model_spec=SimpleModel)

def test_union_type():
    my_inst = MyModel(dict(my_field={'simple_field': 'simple_value'}))
    my_inst.to_primitive()

The error:

============================================================== FAILURES ===============================================================
___________________________________________________________ test_union_type ___________________________________________________________

    def test_union_type():
        my_inst = MyModel(dict(my_field={'simple_field': 'simple_value'}))
>       my_inst.to_primitive()

repro.py:12:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/models.py:309: in to_primitive
    return to_primitive(self._schema, self, role=role, app_data=app_data, **kwargs)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/transforms.py:436: in to_primitive
    return export_loop(cls, instance_or_dict, to_primitive_converter, **kwargs)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/transforms.py:277: in export_loop
    value = _field_converter(field, value, context)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/transforms.py:355: in __call__
    return self.func(*args)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/transforms.py:370: in to_primitive_converter
    return field.export(value, PRIMITIVE, context)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/types/base.py:286: in export
    return self.export_mapping[format](value, context)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/types/union.py:96: in to_primitive
    field, _ = self._resolve(value, context)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/types/union.py:67: in _resolve
    response = self.resolve(value, context)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/types/union.py:59: in resolve
    value = field.convert(value, context)
../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/types/compound.py:48: in convert
    return self._convert(value, context)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <ModelType(SimpleModel) instance>, value = <SimpleModel instance>
context = Context({'initialized': True, 'field_converter': <schematics.transforms.BasicConverter object at 0x7f483c5c5128>, 'role': None, 'raise_error_on_role': True, 'export_level': None, 'app_data': {}})

    def _convert(self, value, context):
        field_model_class = self.model_class
        if isinstance(value, field_model_class):
            model_class = type(value)
        elif isinstance(value, dict):
            model_class = field_model_class
        else:
            raise ConversionError(
                _("Input must be a mapping or '%s' instance") % field_model_class.__name__)
>       if context.convert and context.oo:
E       AttributeError: 'Context' object has no attribute 'convert'

../../../../.venv_terrasphere/lib/python3.6/site-packages/schematics/types/compound.py:156: AttributeError

I was able to work around this issue by creating my own uniontype and overriding export() with the following:

        if isinstance(value, GetAttrModel):
            return self._types[GetAttrType].export(value, format, context)

        return super().export(value, format, context)

acormier128 avatar Aug 13 '18 17:08 acormier128