def __getattribute__(self, attr_name): """Patch the default __getattribute__ call to be better for us. Rather than *only* looking at the __dict__ of the object do determine attribute resolution, improve so that: * Attributes are looked at in the underlying ``rally_data`` stored against the object. * If found in this data and it is a dictionary, load a new python object up with the data. * Otherwise, just return the data. * If not found there, attributes are looked at in ``sub_objects_dynamic_loader``. This is a dictionary of ``property_name`` to ``rally_data`` key. If ``attr_name`` exists in this mapping, the corresponding data is dynamically loaded and returned. * If neither of these yield results, return the standard object __getattribute__ result. """ # Filter out the attributes we require to make decisions in this # method. Otherwise, we'll get "Maximum recursion depth" errors. if attr_name in ['rally_data', 'sub_objects_dynamic_loader', '_full_sub_objects']: return object.__getattribute__(self, attr_name) rally_data = object.__getattribute__(self, 'rally_data') if attr_name in rally_data: rally_item = rally_data[attr_name] if isinstance(rally_item, dict) and '_ref' in rally_item: rally_name = rally_item['_type'] object_class = API_OBJECT_TYPES.get(rally_name, BaseRallyModel) try: return object_class.create_from_ref(rally_item['_ref']) except ReferenceNotFoundException: return None else: return rally_item else: # If it is not in the rally data, let's check if we're trying to # access an auto-loading attribute. if attr_name in self.sub_objects_dynamic_loader: if attr_name not in self._full_sub_objects: rally_data_equivalent = \ self.sub_objects_dynamic_loader[attr_name] self._full_sub_objects[attr_name] = [] for skeleton in self.rally_data.get(rally_data_equivalent, []): rally_name = skeleton['_type'] object_class = API_OBJECT_TYPES.get(rally_name, BaseRallyModel) self._full_sub_objects[attr_name].append( object_class.create_from_ref( skeleton['_ref'])) return self._full_sub_objects[attr_name] return object.__getattribute__(self, attr_name)
def __getattribute__(self, attr_name): """Patch the default __getattribute__ call to be better for us. Rather than *only* looking at the __dict__ of the object do determine attribute resolution, improve so that: * Attributes are looked at in the underlying ``rally_data`` stored against the object. * If found in this data and it is a dictionary, load a new python object up with the data. * Otherwise, just return the data. * If not found there, attributes are looked at in ``sub_objects_dynamic_loader``. This is a dictionary of ``property_name`` to ``rally_data`` key. If ``attr_name`` exists in this mapping, the corresponding data is dynamically loaded and returned. * If neither of these yield results, return the standard object __getattribute__ result. """ # Filter out the attributes we require to make decisions in this # method. Otherwise, we'll get "Maximum recursion depth" errors. if attr_name in [ 'rally_data', 'sub_objects_dynamic_loader', '_full_sub_objects' ]: return object.__getattribute__(self, attr_name) rally_data = object.__getattribute__(self, 'rally_data') if attr_name in rally_data: rally_item = rally_data[attr_name] if isinstance(rally_item, dict) and '_ref' in rally_item: rally_name = rally_item['_type'] object_class = API_OBJECT_TYPES.get(rally_name, BaseRallyModel) try: return object_class.create_from_ref(rally_item['_ref']) except ReferenceNotFoundException: return None else: return rally_item else: # If it is not in the rally data, let's check if we're trying to # access an auto-loading attribute. if attr_name in self.sub_objects_dynamic_loader: if attr_name not in self._full_sub_objects: rally_data_equivalent = \ self.sub_objects_dynamic_loader[attr_name] self._full_sub_objects[attr_name] = [] for skeleton in self.rally_data.get( rally_data_equivalent, []): rally_name = skeleton['_type'] object_class = API_OBJECT_TYPES.get( rally_name, BaseRallyModel) self._full_sub_objects[attr_name].append( object_class.create_from_ref(skeleton['_ref'])) return self._full_sub_objects[attr_name] return object.__getattribute__(self, attr_name)
def convert_from_query_result(cls, results, full_objects=False): """Convert a set of Rally results into python objects. :param results: An iterable of results from the Rally API. :param full_objects: Boolean. If ``True``, ``results`` is assumed to contain full objects as returned by the API when ``fetch=True`` is included in the URL. If ``False``, the full object data is fetched using :py:meth:`~pyrally.models.BaseRallyModel.create_from_ref`. :returns: A list of full :py:class:`~pyrally.models.BaseRallyModel` inheriting python objects. """ converted_results = [] for result in results: object_class = API_OBJECT_TYPES.get(result['_type'], BaseRallyModel) if full_objects: new_obj = object_class(result) else: new_obj = object_class.create_from_ref(result['_ref']) converted_results.append(new_obj) return converted_results