-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Have models inherit from base class, support model polymorphism #128
Conversation
2 similar comments
I can write some additional tests for this, but it would be good to get feedback on what I've got first. |
@jlumpe this is looking really good! Could you add a couple of tests for model polymorphism? Also, do you consider all of your TODOs blockers for shipping this? Some of those seem like separate issues, if you agree please file them accordingly. |
@sjaensch Thanks for reviewing this. I would say other than the tests everything in the TODO list is more of a "nice to have" and can be done in separate PRs later. If this all looks good I can get started on writing the remaining tests right away. Just wanted to confirm that the API is acceptable, I know prefixing non-private methods with an underscore is unconventional but I don't see much of a way around it here. Also, it looks like all the Travis checks for Python 2.6 keep failing due to the use of some 2.7-specific syntax. I'll have to clean that up as well. |
@jlumpe honestly I don't have a better solution that makes sure we won't have name clashes with model fields, so let's do it. |
1 similar comment
Have models inherit from base class, support model polymorphism (continuation of #128)
Re-worked model generation to use a base
Model
class that defines most of the functionality. The current implementation subclassesobject
and adds lambdas with closures to the__dict__
in lieu of methods. This allows for custom extensions as well as I think being cleaner and more Pythonic.One issue with dynamic generation of model classes is that the schema properties could be named anything so there will always be possible conflicts with the base model methods/attributes. I've attempted to minimize this by prefixing all class-level attribute names that are part of the public API with a single underscore. This is unusual but is similar to the
collections.namedtuple
class which also creates dynamic classes with arbitrary attribute names. Truly private attributes are prefixed with a double underscore.Quick list of changes:
Model.__dict
attribute instead of standardModel.__dict__
so that attribute access can be customized.model['prop_name']
. This works for setting and deleting too.del model.property
ordel model['property']
) will set it toNone
instead of deleting it entirely.__iter__
and__contains__
(similar to a dictionary).Model._additional_props
is now dynamic.marshal()
andunmarshal()
methods renamed_marshal()
and_unmarshal()
._to_dict()
gets dictionary of property values.create_model_type()
allows using a custom base class.Model._from_dict()
methodis pretty much the same thing as the new
create()
.Also, polymorphism is now implemented as defined as per the Swagger 2.0 spec. If a model spec has the
discriminator
property defined, this value will be checked when unmarshaling data to choose an alternative model.TODO:
schema['additionalProperties'] == False
raises an exception, but no checking is done when setting attributes afterward.Model.__dir__()
should be more consistent with the standard implementation and return private and class attributes as well. To get the current property names you can just iterate over it. For now I've kept like it was before to pass the existing test.Model.__repr__()
can get very long, maybe truncate it?