def test_attr_or_key_util(): class Foo(object): bar = 'baz' foo_dict = {'bar': 'baz'} invalid = 'str' assert attr_or_key(Foo(), 'bar') == 'baz' assert attr_or_key(Foo(), 'qux') is None assert attr_or_key(foo_dict, 'bar') == 'baz' assert attr_or_key(foo_dict, 'qux') is None assert attr_or_key(invalid, 'bar') is None
def test_attr_or_key_util_dot_syntax(): class Bar(object): xyz = 'abc' class Foo(object): bar = Bar() foo_dict = {'bar': {'xyz': 'abc'}} assert attr_or_key(Foo(), 'bar.xyz') == 'abc' assert attr_or_key(Foo(), 'bar.qux') is None assert attr_or_key(foo_dict, 'bar.xyz') == 'abc' assert attr_or_key(foo_dict, 'bar.qux') is None
def marshall_collection(session): """iterate over each item in ``data`` and marshal the item through the wrapped field defined for this collection :param session: Kim pipeline session instance TODO(mike) this should be called marshal_collection """ wrapped_field = session.field.opts.field existing_value = attr_or_key(session.output, session.field.opts.source) output = [] if session.data is not None: if not hasattr(session.data, '__iter__'): raise session.field.invalid('type_error') for i, datum in enumerate(session.data): _output = {} # If the object already exists, try to match up the existing elements # with those in the input json if existing_value is not None: try: _output[wrapped_field.opts.source] = existing_value[i] except IndexError: pass mapper_session = session.mapper.get_mapper_session(datum, _output) wrapped_field.marshal(mapper_session, parent_session=session) result = _output[wrapped_field.opts.source] output.append(result) session.data = output return session.data
def get_data_from_name(session): """Extracts a specific key from data using ``field.name``. This pipe is typically used as the entry point to a chain of input pipes. :param session: Kim pipeline session instance :rtype: mixed :returns: the key found in data using field.name """ # If the field is wrapped by another field then the relevant data # will have already been pulled from the name. if session.field.opts._is_wrapped: return session.data value = attr_or_key(session.data, session.field.name) if value is None: if session.field.opts.required and session.field.opts.default is None: raise session.field.invalid(error_type='required') elif session.field.opts.default is not None: session.data = session.field.opts.default return session.data elif not session.field.opts.allow_none: raise session.field.invalid(error_type='none_not_allowed') session.data = value return session.data
def marshal_nested(session): """Marshal data using the nested mapper defined on this field. There are 6 possible scenarios, depending on the security setters and presence of a getter function * Getter function returns an object and no updates are allowed - Return the object immediately * Getter function returns an object and updates are allowed - Call the nested mapper with the object to update it * Object already exists, getter function returns None/does not exist and in place updates are allowed - Call the nested mapper with the existing object to update it * Getter function returns None/does not exist and creation of new objects is allowed - Call the nested mapper to create a new object * Getter function returns None/does not exist and creation of new objects is not allowed, nor are in place updates - Raise an exception. * Object already exists, getter function returns None/does not exist and partial updates are allowed - Call the nested mapper with the existing object to update it :param session: Kim pipeline session instance """ resolved = _call_getter(session) partial = session.mapper_session.partial parent_mapper = session.mapper if session.parent and session.parent.nested_mapper: nested_mapper_class = session.parent.nested_mapper else: nested_mapper_class = session.field.get_mapper(as_class=True) if resolved is not None: if session.field.opts.allow_updates: nested_mapper = nested_mapper_class( data=session.data, obj=resolved, partial=partial, parent=parent_mapper) session.data = nested_mapper.marshal(role=session.field.opts.role) else: session.data = resolved else: existing_value = attr_or_key(session.output, session.field.name) if (session.field.opts.allow_updates_in_place or session.field.opts.allow_partial_updates) and \ existing_value is not None: nested_mapper = nested_mapper_class( data=session.data, obj=existing_value, partial=partial, parent=parent_mapper) session.data = nested_mapper.marshal(role=session.field.opts.role) elif session.field.opts.allow_create: nested_mapper = nested_mapper_class( data=session.data, partial=partial, parent=parent_mapper) session.data = nested_mapper.marshal(role=session.field.opts.role) else: raise session.field.invalid(error_type='not_found') return session.data
def marshal_nested(session): """Marshal data using the nested mapper defined on this field. There are 6 possible scenarios, depending on the security setters and presence of a getter function * Getter function returns an object and no updates are allowed - Return the object immediately * Getter function returns an object and updates are allowed - Call the nested mapper with the object to update it * Object already exists, getter function returns None/does not exist and in place updates are allowed - Call the nested mapper with the existing object to update it * Getter function returns None/does not exist and creation of new objects is allowed - Call the nested mapper to create a new object * Getter function returns None/does not exist and creation of new objects is not allowed, nor are in place updates - Raise an exception. * Object already exists, getter function returns None/does not exist and partial updates are allowed - Call the nested mapper with the existing object to update it :param session: Kim pipeline session instance """ resolved = _call_getter(session) partial = session.mapper_session.partial parent = session.mapper if resolved is not None: if session.field.opts.allow_updates: nested_mapper = session.field.get_mapper(data=session.data, obj=resolved, partial=partial, parent=parent) session.data = nested_mapper.marshal(role=session.field.opts.role) else: session.data = resolved else: existing_value = attr_or_key(session.output, session.field.name) if (session.field.opts.allow_updates_in_place or session.field.opts.allow_partial_updates) and \ existing_value is not None: nested_mapper = session.field.get_mapper(data=session.data, obj=existing_value, partial=partial, parent=parent) session.data = nested_mapper.marshal(role=session.field.opts.role) elif session.field.opts.allow_create: nested_mapper = session.field.get_mapper(data=session.data, partial=partial, parent=parent) session.data = nested_mapper.marshal(role=session.field.opts.role) else: raise session.field.invalid(error_type='not_found') return session.data
def check_duplicates(session): """iterate over collection and check for duplicates if th unique_on FieldOpt has been set of this Collection field TODO(mike) This should only run if the wrapped field is a nested collection """ data = session.data key = session.field.opts.unique_on if key: keys = [attr_or_key(a, key) for a in data] if len(keys) != len(set(keys)): raise session.field.invalid(error_type='duplicates') return data
def get_data_from_source(session): """Extracts a specific key from data using ``field.source``. This pipe is typically used as the entry point to a chain of output pipes. :param session: Kim pipeline session instance :rtype: mixed :returns: the key found in data using field.source """ source = session.field.opts.source # If the field is wrapped by another field then the relevant data # will have already been pulled from the source. if session.field.opts._is_wrapped or source == '__self__': return session.data value = attr_or_key(session.data, source) session.data = value return session.data
def test_attr_or_key_util_dot_syntax_escape(): foo_dict = {"bar.xyz": "abc"} assert attr_or_key(foo_dict, "bar\\.xyz") == "abc"