Improve the resolve_attribute function

Update the arguments of the function to be full length and more explicit.
Use exceptions to find the correct way of using the attribute of the
object passed instead of trying to use introspection.
Add support for passing key word arguments to the attribute being
resolved even if it is a class method.

Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2018-12-21 23:41:38 -04:00
parent 9bcaf1849b
commit 79cba7abe1
4 changed files with 37 additions and 29 deletions

View File

@@ -130,29 +130,37 @@ def resolve(path, urlconf=None):
return django_resolve(path=path, urlconf=urlconf)
def resolve_attribute(obj, attrib, arguments=None):
if isinstance(attrib, types.FunctionType):
return attrib(obj)
elif isinstance(obj, dict_type) or isinstance(obj, dictionary_type):
return obj[attrib]
else:
def resolve_attribute(obj, attribute, kwargs=None):
if not kwargs:
kwargs = {}
# Try as a callable
try:
return attribute(obj, **kwargs)
except TypeError:
# Try as a dictionary
try:
result = reduce_function(getattr, attrib.split('.'), obj)
if isinstance(result, types.MethodType):
if arguments:
return result(**arguments)
return obj[attribute]
except TypeError:
try:
# If there are dots in the attribute name, traverse them
# to the final attribute
result = reduce_function(getattr, attribute.split('.'), obj)
try:
# Try it as a method
return result(**kwargs)
except TypeError:
# Try it as a property
return result
except AttributeError:
# Try as a related model field
if LOOKUP_SEP in attribute:
attrib = attribute.replace(LOOKUP_SEP, '.')
return resolve_attribute(
obj=obj, attribute=attribute, kwargs=kwargs
)
else:
return result()
else:
return result
except AttributeError:
if LOOKUP_SEP in attrib:
attrib = attrib.replace(LOOKUP_SEP, '.')
return resolve_attribute(
obj=obj, attrib=attrib, arguments=arguments
)
else:
raise
raise
def return_related(instance, related_field):