Skip to content
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

Json reference #21

Merged
merged 23 commits into from
Dec 14, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ea87ac8
add path2url
mission-liao Dec 2, 2014
11657a2
prepare for resolve external $ref
mission-liao Dec 2, 2014
e47d103
Merge branch 'master' into json_reference
mission-liao Dec 4, 2014
d25c45c
Merge branch 'master' into json_reference
mission-liao Dec 8, 2014
0cfbca0
add container_apply to simplify routine to handle ContainerType
mission-liao Dec 9, 2014
b8466fa
BaseObj.merge now deep copy everything
mission-liao Dec 9, 2014
5c6ec2f
deref of cascade $ref
mission-liao Dec 9, 2014
208b0b0
more test conditions
mission-liao Dec 9, 2014
668526a
prepend / for shortcut
mission-liao Dec 9, 2014
81940de
remove tailing space
mission-liao Dec 9, 2014
b909c34
DFS circle detection
mission-liao Dec 10, 2014
2cf6fb3
fix cycle detection
mission-liao Dec 11, 2014
a7669cb
cycle detection in SwaggerApp.prepare
mission-liao Dec 11, 2014
aa72608
refine code
mission-liao Dec 11, 2014
ba330ad
jr_split
mission-liao Dec 11, 2014
d7e84cf
many refinement
mission-liao Dec 13, 2014
ba2d4d5
refine code to support implicit reference of JSON pointer
mission-liao Dec 13, 2014
9ce8823
keep a strong reference of internally resolved SwaggerApp
mission-liao Dec 13, 2014
a6cf322
complete external document
mission-liao Dec 13, 2014
98f4319
refine
mission-liao Dec 14, 2014
1e884d1
add __swagger_version__ in pyswagger.base.BaseObj
mission-liao Dec 14, 2014
1ab2392
append '#' for JSON reference without JSON pointer
mission-liao Dec 14, 2014
802fd21
external document with partial swagger.json
mission-liao Dec 14, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 87 additions & 49 deletions pyswagger/base.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from __future__ import absolute_import
from .utils import jp_compose
import six
import weakref
import copy
import functools
import weakref


class ContainerType:
Expand All @@ -18,13 +19,43 @@ class ContainerType:
# dict of list container, like: {'xx': [], 'xx': [], ...}
dict_of_list_ = 3

def container_apply(ct, v, f, fd=None, fdl=None):
"""
"""
ret = None
if v == None:
return ret

if ct == None:
ret = f(ct, v)
elif ct == ContainerType.list_:
ret = []
for vv in v:
ret.append(f(ct, vv))
elif ct == ContainerType.dict_:
ret = {}
for k, vv in six.iteritems(v):
ret[k] = fd(ct, vv, k) if fd else f(ct, vv)
elif ct == ContainerType.dict_of_list_:
ret = {}
for k, vv in six.iteritems(v):
if fdl:
fdl(ct, vv, k)
ret[k] = []
for vvv in vv:
ret[k].append(fd(ct, vvv, k) if fd else f(ct, vvv))
else:
raise ValueError('Unknown ContainerType: {0}'.format(ct))

return ret


class Context(object):
""" Base of all parsing contexts """

# required fields, a list of strings
__swagger_required__ = []

# parsing context of children fields,
# a list of tuple (field-name, container-type, parsing-context)
__swagger_child__ = []
Expand Down Expand Up @@ -95,12 +126,26 @@ def parse(self, obj=None):
if not isinstance(obj, dict):
raise ValueError('invalid obj passed: ' + str(type(obj)))

def _apply(x, kk, ct, v):
if key not in self._obj:
self._obj[kk] = {} if ct == None else []
with x(self._obj, kk) as ctx:
ctx.parse(obj=v)

def _apply_dict(x, kk, ct, v, k):
if k not in self._obj[kk]:
self._obj[kk][k] = {} if ct == ContainerType.dict_ else []
with x(self._obj[kk], k) as ctx:
ctx.parse(obj=v)

def _apply_dict_before_list(kk, ct, v, k):
self._obj[kk][k] = []

if hasattr(self, '__swagger_child__'):
# to nested objects
for key, ct, ctx_kls in self.__swagger_child__:
items = obj.get(key, None)

# make all containers to something not None
if ct == ContainerType.list_:
self._obj[key] = []
elif ct:
Expand All @@ -109,26 +154,11 @@ def parse(self, obj=None):
if items == None:
continue

# deep into children
if ct == None:
self._obj[key] = {}
with ctx_kls(self._obj, key) as ctx:
ctx.parse(obj=items)
elif ct == ContainerType.list_:
for item in items:
with ctx_kls(self._obj, key) as ctx:
ctx.parse(obj=item)
elif ct == ContainerType.dict_:
for k, v in six.iteritems(items):
self._obj[key][k] = {}
with ctx_kls(self._obj[key], k) as ctx:
ctx.parse(obj=v)
elif ct == ContainerType.dict_of_list_:
for k, v in six.iteritems(items):
self._obj[key][k] = []
for vv in v:
with ctx_kls(self._obj[key], k) as ctx:
ctx.parse(obj=vv)
container_apply(ct, items,
functools.partial(_apply, ctx_kls, key),
functools.partial(_apply_dict, ctx_kls, key),
functools.partial(_apply_dict_before_list, key)
)

# update _obj with obj
if self._obj != None:
Expand All @@ -150,6 +180,10 @@ class BaseObj(object):
# - tuple(string, default-value): a field name with default value
__swagger_fields__ = []


# Swagger Version this object belonging to
__swagger_version__ = None

def __init__(self, ctx):
""" constructor

Expand All @@ -173,7 +207,7 @@ def __init__(self, ctx):
def _assign_parent(self, ctx):
""" parent assignment, internal usage only
"""
def _assign(cls, obj):
def _assign(cls, _, obj):
if obj == None:
return

Expand All @@ -189,22 +223,7 @@ def _assign(cls, obj):
if obj == None:
continue

# iterate through children by ContainerType
if ct == None:
_assign(ctx, obj)
elif ct == ContainerType.list_:
for v in obj:
_assign(ctx, v)
elif ct == ContainerType.dict_:
for v in obj.values():
_assign(ctx, v)
elif ct == ContainerType.dict_of_list_:
for v in obj.values():
for vv in v:
_assign(ctx, vv)
else:
raise ValueError('Unknown ContainerType: {0}'.format(ct))

container_apply(ct, obj, functools.partial(_assign, ctx))

def get_private_name(self, f):
""" get private protected name of an attribute
Expand Down Expand Up @@ -245,19 +264,38 @@ def resolve(self, ts):

return obj

def merge(self, other):
def merge(self, other, ctx):
""" merge properties from other object,
only merge from 'not None' to 'None'.
"""
for name, _ in self.__swagger_fields__:
def _produce_new_obj(x, ct, v):
return x(None, None).produce().merge(v, x)

for name, default in self.__swagger_fields__:
v = getattr(other, name)
if v != None and getattr(self, name) == None:
if isinstance(v, weakref.ProxyTypes):
self.update_field(name, v)
elif isinstance(v, BaseObj):
self.update_field(name, weakref.proxy(v))
else:
self.update_field(name, v)
if v == default or getattr(self, name) != default:
continue

childs = [c for c in ctx.__swagger_child__ if c[0] == name]
if len(childs) == 0:
# we don't need to make a copy,
# since everything under SwaggerApp should be
# readonly.
self.update_field(name, v)
continue

ct, cctx = childs[0][1], childs[0][2]
self.update_field(name,
container_apply(
ct, v,
functools.partial(_produce_new_obj, cctx)
))

# make sure parent is correctly assigned.
self._assign_parent(ctx)

# allow cascade calling
return self

@property
def _parent_(self):
Expand Down
Loading