Data structures =============== A data returned from successful API calls are transformed and presented to you as a [Munch](https://github.com/Infinidat/munch) (it is a subclass of a ``dict`` with all its features, with an additional support of accessing its attributes like object properties, etc). This page shows how to work with the results, how to access the original responses from frontend and what are the specifics for lists of results. First, let's just initialize an API client, and obtain some object (in this example a build) to be examined. :: from copr.v3 import Client from pprint import pprint client = Client.create_from_config_file() build = client.build_proxy.get(2545) pprint(build) As advertised, the data is represented as a [Munch](https://github.com/Infinidat/munch). :: Munch({u'source_package': {u'url': u'http://backend/results//@copr/copr/srpm-builds/00002545/ed-1.14.2-3.fc26.src.rpm', u'version': u'1.14.2-3.fc26', u'name': u'ed'}, '__response__': , u'projectname': u'copr', u'started_on': 1526406595, u'submitted_on': 1525635534, u'state': u'succeeded', u'ended_on': 1526408106, u'ownername': u'@copr', u'repo_url': u'http://backend/results/@copr/copr', u'submitter': u'frostyx', u'chroots': [u'fedora-27-x86_64', u'fedora-rawhide-x86_64'], u'id': 2545}) What exactly it is? It is a structure that extends ``dict`` and add more features to it. :: print(type(build)) print(isinstance(build, dict)) :: True In the first example, it is quite hard to see, what attributes are available and what are their values. It is possible to print the structure in more human-readable format. :: from pprint import pprint pprint(dict(build)) :: {'__response__': , u'chroots': [u'fedora-27-x86_64', u'fedora-rawhide-x86_64'], u'ended_on': 1526408106, u'id': 2545, u'ownername': u'@copr', u'projectname': u'copr', u'repo_url': u'http://backend/results/@copr/foo', u'source_package': {u'name': u'ed', u'url': u'http://backend/results//@copr/copr/srpm-builds/00002545/ed-1.14.2-3.fc26.src.rpm', u'version': u'1.14.2-3.fc26'}, u'started_on': 1526406595, u'state': u'succeeded', u'submitted_on': 1525635534, u'submitter': u'frostyx'} Attributes are accessible through standard dict bracket-style, but also through object like property-style. :: assert build.ownername == build["ownername"] print(build.ownername) :: @copr Every data munch also stores the original response from frontend. :: print(build.__response__) print(type(build.__response__)) print(build.__response__.status_code) :: requests.models.Response 200 Lists of objects ---------------- Now, it should be clear how a single data object is represented. Let's see how the situation looks like when multiple objects are returned. :: builds = client.build_proxy.get_list("@copr", "copr") print(builds) At the first sight, it is just a list of munches. :: [Munch({u'source_package': {u'url': u'http://backend/results//@copr/copr/srpm-builds/00002544/mksh-56c-3.fc26.src.rpm', u'version': u'56c-3.fc26', u'name': u'mksh'}, u'projectname': u'copr', u'started_on': 1519063348, u'submitted_on': 1519062565, u'state': u'succeeded', u'ended_on': 1519064069, u'ownername': u'frostyx', u'repo_url': u'http://backend/results/@copr/copr', u'submitter': u'frostyx', u'chroots': [u'fedora-rawhide-i386', u'fedora-rawhide-x86_64'], u'id': 2544}), Munch({u'source_package': {u'url': u'http://backend/results//@copr/copr/srpm-builds/00002545/ed-1.14.2-3.fc26.src.rpm', u'version': u'1.14.2-3.fc26', u'name': u'ed'}, u'projectname': u'copr', u'started_on': 1526406595, u'submitted_on': 1525635534, u'state': u'succeeded', u'ended_on': 1526408106, u'ownername': u'@copr', u'repo_url': u'http://backend/results/@copr/copr', u'submitter': u'frostyx', u'chroots': [u'fedora-27-x86_64', u'fedora-rawhide-x86_64'], u'id': 2545})] Not exactly. It is a subclass of a ``list`` created in the ``copr`` package. :: print(type(builds)) print(isinstance(builds, list)) :: True Let's answer the anticipated question, why do we need a modified implementation of a list. It can provide the frontend response in a ``__response__`` attribute the same way that single munch does. :: print(builds.__response__) It also provides a ``meta`` attribute, that has information about ordering results in the list and possibly limiting their number. Please read more about the pagination. :: print(builds.meta) Munch({u'offset': 0, u'limit': None, u'order_type': u'ASC', u'order': u'id'}) Iterating through all objects in the response looks as expected. :: for build in builds: print("Build {} {}".format(build.id, build.state)) :: Build 2544 succeeded Build 2545 succeeded Modifying data -------------- Previous examples show the data structures when the object was explicitly queried (i.e. ``get`` or ``get_list`` method was used). It remains to be explained, how the responses look like when a user tries to add, modify, or delete some object. Simply enough, the operation is executed and the object is implicitly queried afterward. :: build = client.build_proxy.delete(2545) print(build) :: Munch({u'source_package': {u'url': u'http://backend/results//@copr/copr/srpm-builds/00002545/ed-1.14.2-3.fc26.src.rpm', u'version': u'1.14.2-3.fc26', u'name': u'ed'}, u'projectname': u'copr', u'started_on': 1526406595, u'submitted_on': 1525635534, u'state': u'succeeded', u'ended_on': 1526408106, u'ownername': u'@copr', u'repo_url': u'http://backend/results/@copr/copr', u'submitter': u'frostyx', u'chroots': [u'fedora-27-x86_64', u'fedora-rawhide-x86_64'], u'id': 2545}) The object was deleted, so it obviously can't be queried one more time :: client.build_proxy.get(build.id) :: CoprNoResultException: Build 2545 does not exist.