def _encode(inner_obj): encoded = inner_obj # encode resource objects with their specified serializer, # according to the highest level of access which the environment arguments allow if getattr(inner_obj, '_IS_RESOURCE', False): # determine the access level in this environment permission = self._access_level(obj, environment) # retrieve the serializer serializer = getattr(inner_obj, self.serialization_method_name, None) if serializer is not None: # encode the resource using its serializer with the provided permission serializer_kwargs = populate_args(serializer, {'permission': permission}, environment) encoded = serializer(**serializer_kwargs) else: raise ValueError("Unable to serialize: object '" + obj.__name__ + "' has no method '" + self.serialization_method_name + "'") elif isinstance(inner_obj, collections.Mapping): # recurse on dictionary-like objects encoded = {} for key, val in inner_obj.iteritems(): encoded[key] = _encode(val) elif isinstance(inner_obj, collections.Iterable): # recurse on array-like objects encoded = [] for val in inner_obj: encoded.append(_encode(val)) return encoded
def _commit(self, name, instance, environment, encode=True): commit_result = None # commit changes to the resource if self.is_transactional.get(name, True): commit_method = getattr(instance, self.commit_method_name, None) if commit_method is not None: commit_kwargs = populate_args(commit_method, environment) commit_result = commit_result(**commit_kwargs) if encode: commit_result = self.encode(commit_result, environment) return commit_result
def _access_level(self, resource_instance, environment): """Determine a resource's most restrictive access permission for a given environment""" # determine if the resource instance has a method to provide the # highest level of access this environment can give access_level_method = getattr(resource_instance, self.access_level_method_name, None) if access_level_method is not None: access_level_kwargs = populate_args(access_level_method, environment) access_level = access_level_method(**access_level_kwargs) else: # fall back on calling its access method in the provided # permissions order access_method = getattr(resource_instance, self.access_method_name, None) access_level = None if access_method is not None: for permission in self.permission_order: access_kwargs = populate_args(access_method, {'permission': permission}, environment) if access_method(**access_kwargs): access_method = permission break return access_level
def _call(self, class_obj, parent, methods, access_method_name, environment, allowed_method_types=None, encode=True): """Performs access and permission checking, calls each specified method (its arguments are combined with the provided environment). """ # look up the access method to check for access access_method = getattr(parent, access_method_name, None) if access_method is None: raise ResourceMethodNotFoundError("'" + class_obj.__name__ + "' is missing an access method") # check if this is an acceptable method of execution as per allowed_method_types if allowed_method_types is not None and method._method_type not in allowed_method_types: raise ResourceNotAllowedError("'" + class_obj.__name__ + "' is not allowed to access '" + method_name + "' in this manner") # check that access can be granted to call this method permission = method._permission access_kwargs = populate_args(access_method, {'permission': permission}, environment) if not access_method(**access_kwargs): raise ResourceAccessDeniedError("'" + class_obj.__name__ + "' has denied access to '" + method_name + "'") result = [] for method_data in methods: if isinstance(method_data, basestring): method_name = method_data sent_arguments = {} else: method_name = method_data.get('method') sent_arguments = method_data.get('args') method_name = method_name.lower() if method_name in self.method_names: err = ResourceMethodNotFoundError("'" + class_obj.__name__ + "' cannot export method '" + method_name + "'") err.method = method_name err.args = sent_arguments raise err class_method = getattr(class_obj, method_name, None) if isinstance(class_method, property): # this "method" is a decorated property num_args = len(sent_arguments) try: if num_args == 0: result.append(getattr(parent, method_name)) elif method_name in sent_arguments: value = sent_arguments[method_name] setattr(parent, method_name, value) result.append(value) except Exception as original_err: # pass on the error information trace = sys.exc_info()[2] err = ResourceMethodFailedError("'" + class_obj.__name__ + "' failed to execute '" + method_name + "'") err.method = method_name err.args = sent_arguments err.error = original_err err.trace = trace raise err, None, trace elif callable(class_method): # this is a callable method # lookup the method and ensure it is exported method = getattr(parent, method_name, None) if method is None or not getattr(method, '_is_exported', False): err = ResourceMethodNotFoundError("'" + class_obj.__name__ + "' has no exported method '" + method_name + "'") err.method = method_name err.args = sent_arguments raise err method_kwargs = populate_args(method, sent_arguments, environment) try: call_result = method(**method_kwargs) except Exception as original_err: # pass on the error information trace = sys.exc_info()[2] err = ResourceMethodFailedError("'" + class_obj.__name__ + "' failed to execute '" + method_name + "'") err.method = method_name err.args = sent_arguments err.error = original_err err.trace = trace raise err, None, trace result.append(call_result) else: err = ResourceMethodNotFoundError("'" + class_obj.__name__ + "' has no method or decorated property '" + method_name + "'") err.method = method_name err.args = sent_arguments raise err if encode: result = self.encode(result, environment) return result