def _map_pks(self, parent_properties): """ Takes a dictionary of the values of the parent resources properties. It then maps those properties to the named properties of the related resource and creates a dictionary of the related resources property values. Raises a KeyError if the parent does not contain keys that matches every key in the self.property_map :param dict parent_properties: A dictionary of the parent resource's properties. The key is the name of the property and the value is the parent resources value for that property :return: A dictionary of the related resources properties. The key is the name of the related resource's property and the value is the value of that resource's property. :rtype: :py:class:`dict` :raises: KeyError """ properties = {} for parent_prop, prop in six.iteritems(self.property_map): val = get_or_pop(parent_properties, parent_prop, pop=self.remove_properties) if val is not None: properties[prop] = val name_values = get_or_pop(parent_properties, self.name, pop=self.remove_properties) if name_values: properties.update(name_values) return properties
def _map_pks(self, parent_properties_orig): """ Takes a dictionary of the values of the parent resources properties. It then maps those properties to the named properties of the related resource and creates a dictionary of the related resources property values. Raises a KeyError if the parent does not contain keys that matches every key in the self.property_map :param dict parent_properties: A dictionary of the parent resource's properties. The key is the name of the property and the value is the parent resources value for that property :return: A dictionary of the related resources properties. The key is the name of the related resource's property and the value is the value of that resource's property. :rtype: :py:class:`dict` :raises: KeyError """ properties = {} parent_properties = parent_properties_orig.copy() # or copy? parprop = parent_properties.copy() # Use the mapper to translate the properties for parent_prop, prop in six.iteritems(self.property_map): val = get_or_pop(parent_properties, parent_prop, pop=self.remove_properties) if val is not None: _logger.info( "Value found for key <{0}> sent to related object <{1}> - <{2}> is available in {3}" .format(prop, self._relation, parent_prop, parprop)) properties[prop] = val else: _logger.warn( "No value found for key <{0}> sent to related object <{1}> - <{2}> is not available in {3}" .format(prop, self._relation, parent_prop, parprop)) # Also copy the properties where the name is equal to the resource name # TODO: Why? What is this for? name_values = get_or_pop(parent_properties, self.name, pop=self.remove_properties) if name_values: try: properties.update(name_values) except ValueError: properties[self.name] = name_values # Also copy remaining, non-translated properties. TODO: There is no reason not to, right? for prop_name, prop in six.iteritems(parent_properties): properties[prop_name] = prop return properties
def test_get_or_pop(self): """Simple test to ensure that the get_or_pop returns the value and appropriately updates the dictionary if necessary""" x = dict(x=1) val = get_or_pop(x, 'x', pop=False) self.assertDictEqual(x, dict(x=1)) self.assertEqual(val, 1) val = get_or_pop(x, 'x', pop=True) self.assertDictEqual(x, dict()) self.assertEqual(val, 1)
def test_get_or_pop_default(self): """Ensures that a default is returned if the key is not available""" x = dict() val = get_or_pop(x, 'x', pop=False) self.assertIsNone(val) val = get_or_pop(x, 'x', pop=True) self.assertIsNone(val) val = get_or_pop(x, 'x', default=1, pop=False) self.assertEqual(val, 1) val = get_or_pop(x, 'x', default=1, pop=True) self.assertEqual(val, 1)
def _map_pks(self, parent_properties_orig): """ Takes a dictionary of the values of the parent resources properties. It then maps those properties to the named properties of the related resource and creates a dictionary of the related resources property values. Raises a KeyError if the parent does not contain keys that matches every key in the self.property_map :param dict parent_properties: A dictionary of the parent resource's properties. The key is the name of the property and the value is the parent resources value for that property :return: A dictionary of the related resources properties. The key is the name of the related resource's property and the value is the value of that resource's property. :rtype: :py:class:`dict` :raises: KeyError """ properties = {} parent_properties = parent_properties_orig.copy() # or copy? parprop = parent_properties.copy() # Use the mapper to translate the properties for parent_prop, prop in six.iteritems(self.property_map): val = get_or_pop(parent_properties, parent_prop, pop=self.remove_properties) if val is not None: _logger.info("Value found for key <{0}> sent to related object <{1}> - <{2}> is available in {3}".format(prop, self._relation, parent_prop, parprop)) properties[prop] = val else: _logger.warn("No value found for key <{0}> sent to related object <{1}> - <{2}> is not available in {3}".format(prop, self._relation, parent_prop, parprop)) # Also copy the properties where the name is equal to the resource name # TODO: Why? What is this for? name_values = get_or_pop(parent_properties, self.name, pop=self.remove_properties) if name_values: try: properties.update(name_values) except ValueError: properties[self.name] = name_values # Also copy remaining, non-translated properties. TODO: There is no reason not to, right? for prop_name, prop in six.iteritems(parent_properties): properties[prop_name] = prop return properties
def construct_resource(self, properties): """ Takes a list of properties and returns a generator that yields Resource instances. These related ResourceBase subclass will be asked to construct an instance with the keyword argument properties equal to each item in the list of properties provided to this function. :param dict properties: A dictionary of the properties on the parent model. The list_name provided in the construction of an instance of this class is used to find the list that will be iterated over to generate the resources. :return: A generator that yields the relationships. :rtype: types.GeneratorType """ resource_name = self.relation.resource_name objects = get_or_pop(properties, resource_name, [], pop=self.remove_properties) resources = [] for obj in objects: res = super().construct_resource(obj) # res = self.relation(properties=obj, query_args=self.query_args, # include_relationships=self.embedded) resources.append(res) if not resources: return None return resources