-
Notifications
You must be signed in to change notification settings - Fork 508
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
add: Wildcard fields #255
add: Wildcard fields #255
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, according to the swagger specs, we are exactly in the case of additionalProperties
. They are not properly documented in the swagger specification, they appear only once in the schema section.
Here is a Stackoverflow post explaining it's behavior.
So we need something else to map to additionnalProperties
.
Proposal: instead of a field definition, we allow an optionnal third parameter to model factory to define additionnalProperties
.
An we need to improve marshalling performance. Here the impact is way to high for models not using it.
Available on gitter to discuss this.
tests/test_fields.py
Outdated
def test_defaults(self): | ||
field = fields.Wildcard(fields.String) | ||
assert not field.required | ||
assert field.__schema__ == {'type': 'array', 'items': {'type': 'string'}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, I don't think the resulting data is an array. I think we need to make use of additionalProperties
. See my review comment for details.
flask_restplus/marshalling.py
Outdated
keys.append(key) | ||
items.append((key, value)) | ||
|
||
items = tuple(items) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry but I can't let that happen this way. I'm currently trying to improve serialization performances which dropped in last releases and this is masively reducing it. We need to find another way, something more efficient.
(I'm talking about the whole marshalling changeset, not the last line)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand the issue here, but the Wildcard thing will require deep introspection and thus, people can/may/should expect slow results.
flask_restplus/fields.py
Outdated
else: | ||
self._flat = [] | ||
attributes = inspect.getmembers(obj, lambda a: not(inspect.isroutine(a))) | ||
for (key, val) in [a for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be done in a single iteration:
Something like:
def match_attribute(attr): # defined once outside
return not(inspect.isroutine(attr) or (attr.__name__.startswith('__') and attr.__name__.endswith('__')))
self._flat.extend(inspect.getmembers(obj, match_attributes))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not completely doable, however, I managed to improve this a bit.
Hi, I tried to rework the Wildcard marshalling in order to reduce performance impact. The impact should be null for any other fields. Also, I would definitely need some help about the |
Here are the benchmark results on my development machine with the Wildcards patch:
And here are the benchmark results on my development machine without the Wildcards patch:
|
Hi, I finally tried to apply the requested change for the schema definition. Here is the result: "Languages":{
"properties":{
"*":{
"type":"object",
"description":"Supported languages",
"additionalProperties":{
"type":"string"
}
}
},
"type":"object"
} Using the following model: wild = fields.Wildcard(fields.String, description='Supported languages')
languages_fields = ns.model('Languages', {
'*': wild,
}) I think this is not 100% correct yet though. We should skip one level and have something like this instead: "Languages":{
"type":"object",
"description":"Supported languages",
"additionalProperties":{
"type":"string"
}
} But this would mean the field type Thoughts? |
I tried to improve wildcard parsing performances. I don't have any benchmark but I expect results to be slightly better. |
flask_restplus/fields.py
Outdated
if obj == self._obj and self._flat is not None: | ||
return self._flat | ||
if isinstance(obj, dict): | ||
self._flat = [x for x in obj.items()] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, should use six.viewitems()
for Python 2x3 compatibility.
Any news? |
To be honnest I can't currently merge this PR:
I like the feature but we need to find a way to properly integrate it without breaking the current behavior and without performances changes for users not using it. I'm ready to discuss it. Don't hesite to PM me on gitter so we can discuss it |
What performance hit? I listened to your review and then corrected my implementation accordingly. The behavior remains unchanged for anything else then the wildcard field. |
This PR adds the ability to define models based on wildcard fields name as requested in #172.