From 670f2ea9f536ac9fccc0b508f33455fc78cb9f23 Mon Sep 17 00:00:00 2001 From: Cameron Hurst Date: Sat, 14 Jul 2018 18:24:28 -0400 Subject: [PATCH 1/2] Add expand and attributes to get and filter methods. Also added support for wrapping list of dictionaries that are manageiq objects on Entity reload. This helps with things like when you expand and get a list of dictionaries back. These are now wrapped as entities that you can work with rather than dictionaries. Added the same thing for dictionaries as well. --- src/manageiq_client/api.py | 43 +++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/manageiq_client/api.py b/src/manageiq_client/api.py index 66910d1..56613b2 100644 --- a/src/manageiq_client/api.py +++ b/src/manageiq_client/api.py @@ -4,13 +4,14 @@ import json import logging import re -import requests -import simplejson -import six -import iso8601 from copy import copy from distutils.version import LooseVersion from functools import partial + +import iso8601 +import requests +import simplejson +import six from wait_for import wait_for from .filters import Q @@ -208,14 +209,14 @@ def __contains__(self, collection): class SearchResult(object): - def __init__(self, collection, data): + def __init__(self, collection, data, attributes=None, expand=None): self.collection = collection self.count = data.pop("count", 0) self.subcount = data.pop("subcount", 0) self.name = data.pop("name") self.resources = [] for resource in data["resources"]: - self.resources.append(Entity(collection, resource)) + self.resources.append(Entity(collection, resource, attributes=attributes, expand=expand)) def __iter__(self): for resource in self.resources: @@ -296,39 +297,43 @@ def query_string(self, **params): """ return SearchResult(self, self._api.get(self._href, **params)) - def raw_filter(self, filters): + def raw_filter(self, filters, attributes=None, expand=None): """Sends all filters to the API. No fancy, just a wrapper. Any advanced functionality shall be implemented as another method. Args: filters: List of filters (strings) + attributes: List of attributes to include in the query of result + expand: List of properties to expand Returns: :py:class:`SearchResult` """ - return SearchResult(self, self._api.get(self._href, **{"filter[]": filters})) + return SearchResult(self, self._api.get(self._href, **{"filter[]": filters}), attributes=attributes, expand=expand) - def filter(self, q): + def filter(self, q, attributes=None, expand=None): """Access the ``filter[]`` functionality of ManageIQ. Args: q: An instance of :py:class:`filters.Q` + attributes: List of attributes to include in the query of result + expand: List of properties to expand Returns: :py:class:`SearchResult` """ - return self.raw_filter(q.as_filters) + return self.raw_filter(q.as_filters, attributes=attributes, expand=expand) - def find_by(self, **params): + def find_by(self, attributes=None, expand=None, **params): """Searches in ManageIQ using the ``filter[]`` get parameter. This method only supports logical AND so all key/value pairs are considered as equality comparision and all are logically anded. """ - return self.filter(Q.from_dict(params)) + return self.filter(Q.from_dict(params), attributes=attributes, expand=expand) - def get(self, **params): + def get(self, attributes=None, expand=None, **params): try: - return self.find_by(**params)[0] + return self.find_by(attributes=attributes, expand=expand, **params)[0] except IndexError: raise ValueError("No such '{}' matching query {!r}!".format(self.name, params)) @@ -398,12 +403,13 @@ class Entity(object): roles={"features"}, ) - def __init__(self, collection, data, incomplete=False, attributes=None): + def __init__(self, collection, data, incomplete=False, attributes=None, expand=None): self.collection = collection self.action = ActionContainer(self) self._data = data self._incomplete = incomplete self._attributes = attributes + self._expand = expand self._href = None self._load_data() @@ -418,6 +424,8 @@ def _load_data(self): def reload(self, expand=None, get=True, attributes=None): kwargs = {} + if expand is None: + expand = self._expand if expand: if isinstance(expand, (list, tuple)): expand = ",".join(map(str, expand)) @@ -463,6 +471,11 @@ def reload(self, expand=None, get=True, attributes=None): href += "/" subcol = Collection(self.collection._api, href + key, key) setattr(self, key, subcol) + elif isinstance(value, list) and all(isinstance(x, dict) and x.get('href', False) for x in value): + entities = list(Entity(self.collection, x) for x in value) + setattr(self, key, entities) + elif isinstance(value, dict) and value.get('href', False): + setattr(self, key, Entity(self.collection, value)) else: setattr(self, key, value) From 4107e747169337bcbc0a4c48b72aa35ee01812fb Mon Sep 17 00:00:00 2001 From: Cameron Hurst Date: Mon, 7 Jan 2019 10:54:14 -0500 Subject: [PATCH 2/2] load rather than reload data so if prepopulated it doesn't call again --- src/manageiq_client/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/manageiq_client/api.py b/src/manageiq_client/api.py index 56613b2..ad9194e 100644 --- a/src/manageiq_client/api.py +++ b/src/manageiq_client/api.py @@ -225,7 +225,7 @@ def __iter__(self): def __getitem__(self, position): entity = self.resources[position] - entity.reload() + entity._load_data() return entity def __len__(self): @@ -309,7 +309,7 @@ def raw_filter(self, filters, attributes=None, expand=None): Returns: :py:class:`SearchResult` """ - return SearchResult(self, self._api.get(self._href, **{"filter[]": filters}), attributes=attributes, expand=expand) + return SearchResult(self, self._api.get(self._href, **{"filter[]": filters, "attributes": attributes, "expand": expand}), attributes=attributes, expand=expand) def filter(self, q, attributes=None, expand=None): """Access the ``filter[]`` functionality of ManageIQ.