Skip to content

Commit

Permalink
issue #172: spec/buggy Path/Operation handling (#188)
Browse files Browse the repository at this point in the history
* issue #172: spec/buggy Path/Operation handling

Current code expect Path object to contain only method/Operation
declaration. Path object may contain $ref, summary, description, servers
and parameters entries.

If available, this entries are default values to apply children
Operation.

This fix drops unused entries ($ref, summary, description, servers) and
merge parameters:
* unicity based on name/in unicity
* Operation value takes precedence

This fix allows to parse spec file attached with #172

* issue #172: fix regression for $ref params

Parameter may be a ``{ '$ref': '...' }``. We need to use $ref, name, in
attributes for processing parameter list merging.

* issue #172: added testcase and fix

Path and methods parameters are merged to handle completion.

Merge process is fixed to allow completion when parameters are
configured only at path level.
  • Loading branch information
lalmeras committed Feb 7, 2021
1 parent 6ce106a commit ac598fd
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 2 deletions.
29 changes: 27 additions & 2 deletions http_prompt/context/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,41 @@ def __init__(self, url=None, spec=None):
elif path[-1] == '/': # Path ends with a trailing slash
path_tokens[-1] = path_tokens[-1] + '/'
self.root.add_path(*path_tokens)
endpoint = paths[path]
endpoint = dict(paths[path])
# path parameters (apply to all paths if not overriden)
# exclude $ref as we have no system to handle that now
global_parameters = list(endpoint.pop('parameters', []))
# not used
endpoint.pop('servers', None)
endpoint.pop('$ref', None)
endpoint.pop('summary', None)
endpoint.pop('description', None)
for method, info in endpoint.items():
params = info.get('parameters')
params = info.get('parameters', [])
params = list(global_parameters + params)
if params:
parameter_key = lambda i: (
i.get('$ref', None),
i.get('name', None),
i.get('in', None)
)
# parameter is overriden based on $ref/in/name value
# last value (local definition) takes precedence
params_map = dict([
(parameter_key(p), p)
for p in params
])
params = params_map.values()
for param in params:
if param.get("$ref"):
for section in param.get("$ref").split('/'):
param = param.get(section) if not section == "#" else spec

if param.get('in') != 'path':
# Note that for completion mechanism, only
# name/node_type is used
# Parameters from methods/location
# are merged
full_path = path_tokens + [param['name']]
self.root.add_path(*full_path,
node_type='file')
Expand Down
53 changes: 53 additions & 0 deletions tests/context/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,56 @@ def test_spec():
assert len(users_children) == 2
assert users_children[0].name == 'Accept'
assert users_children[1].name == 'since'


def test_override():
"""Parameters can be defined at path level
"""
c = Context('http://localhost', spec={
'paths': {
'/users': {
'parameters': [
{'name': 'username', 'in': 'query'},
{'name': 'Accept', 'in': 'header'}
],
'get': {
'parameters': [
{'name': 'custom1', 'in': 'query'}
]
},
'post': {
'parameters': [
{'name': 'custom2', 'in': 'query'},
]
},
},
'/orgs': {
'parameters': [
{'name': 'username', 'in': 'query'},
{'name': 'Accept', 'in': 'header'}
],
'get': {}
}
}
})
assert c.url == 'http://localhost'

root_children = list(sorted(c.root.children))
# one path
assert len(root_children) == 2
assert root_children[0].name == 'orgs'
assert root_children[1].name == 'users'

orgs_methods = list(sorted(list(root_children)[0].children))
# path parameters are used even if no method parameter
assert len(orgs_methods) == 2
assert next(filter(lambda i:i.name == 'username', orgs_methods), None) is not None
assert next(filter(lambda i:i.name == 'Accept', orgs_methods), None) is not None

users_methods = list(sorted(list(root_children)[1].children))
# path and methods parameters are merged
assert len(users_methods) == 4
assert next(filter(lambda i:i.name == 'username', users_methods), None) is not None
assert next(filter(lambda i:i.name == 'custom1', users_methods), None) is not None
assert next(filter(lambda i:i.name == 'custom2', users_methods), None) is not None
assert next(filter(lambda i:i.name == 'Accept', users_methods), None) is not None

0 comments on commit ac598fd

Please sign in to comment.