Merge branch '19954-permission-dedup-doc'
[arvados.git] / doc / sdk / python / api-client.html.textile.liquid
1 ---
2 layout: default
3 navsection: sdk
4 navmenu: Python
5 title: Arvados API Client
6 ...
7 {% comment %}
8 Copyright (C) The Arvados Authors. All rights reserved.
9
10 SPDX-License-Identifier: CC-BY-SA-3.0
11 {% endcomment %}
12 {% comment %}
13 A note about scope for future authors: This page is meant to be a general guide to using the API client. It is intentionally limited to using the general resource methods as examples, because those are widely available and should be sufficient to give the reader a general understanding of how the API client works. In my opinion we should not cover resource-specific API methods here, and instead prefer to cover them in the cookbook or reference documentation, which have a more appropriate scope.  --Brett 2022-12-06
14 {% endcomment %}
15
16 The Arvados Python SDK provides a complete client interface to the "Arvados API":{{site.baseurl}}/api/index.html. You can use this client interface directly to send requests to your Arvados API server, and many of the higher-level interfaces in the Python SDK accept a client object in their constructor for their use. Any Arvados software you write in Python will likely use these client objects.
17
18 This document explains how to instantiate the client object, and how its methods map to the full "Arvados API":{{site.baseurl}}/api/index.html. Refer to the API documentation for full details about all available resources and methods. The rest of the Python SDK documentation after this covers the higher-level interfaces it provides.
19
20 h2. Initializing the API client
21
22 In the simplest case, you can import the @arvados@ module and call its @api@ method with an API version number:
23
24 {% codeblock as python %}
25 import arvados
26 arv_client = arvados.api('v1')
27 {% endcodeblock %}
28
29 This will connect to the Arvados API server using the @ARVADOS_API_HOST@, @ARVADOS_API_TOKEN@, and @ARVADOS_API_HOST_INSECURE@ settings from environment variables or @~/.config/arvados/settings.conf@. You can alternatively pass these settings as arguments:
30
31 {% codeblock as python %}
32 import arvados
33 arv_client = arvados.api(
34     'v1',
35     host='api.arvados.example.com',
36     token='ExampleToken',
37     insecure=False,
38 )
39 {% endcodeblock %}
40
41 Either way, you can now use the @arv_client@ object to send requests to the Arvados API server you specified, using the configured token. The client object queries the API server for its supported API version and methods, so this client object will always support the same API the server does, even when there is a version mismatch between it and the Python SDK.
42
43 h2. Resources, methods, and requests
44
45 The API client has a method that corresponds to each "type of resource supported by the Arvados API server":{{site.baseurl}}/api/ (listed in the documentation sidebar). You call these methods without any arguments. They return a resource object you use to call a method on that resource type.
46
47 Each resource object has a method that corresponds to each API method supported by that resource type. You call these methods with the keyword arguments and values documented in the API reference. They return an API request object.
48
49 Each API request object has an @execute()@ method. You may pass a @num_retries@ integer argument to retry the operation that many times, with exponential back-off, in case of temporary errors like network problems. If it ultimately succeeds, it returns the kind of object documented in the API reference for that method. Usually that's a dictionary with details about the object you requested. If there's a problem, it raises an exception.
50
51 Putting it all together, basic API requests usually look like:
52
53 {% codeblock as python %}
54 arv_object = arv_client.resource_type().api_method(
55     argument=...,
56     other_argument=...,
57 ).execute(num_retries=3)
58 {% endcodeblock %}
59
60 The following sections detail how to call "common resource methods in the API":{{site.baseurl}}/api/methods.html with more concrete examples. Additional methods may be available on specific resource types.
61
62 h2. get method
63
64 To fetch a single Arvados object, call the @get@ method of the resource type. You must pass a @uuid@ argument string that identifies the object to fetch. The method returns a dictionary with the object's fields.
65
66 {% codeblock as python %}
67 # Get a workflow and output its Common Workflow Language definition
68 workflow = api.workflows().get(uuid='zzzzz-7fd4e-12345abcde67890').execute()
69 print(workflow['definition'])
70 {% endcodeblock %}
71
72 You can pass a @select@ argument that's a list of field names to return in the included object. Doing this avoids the overhead of de/serializing and transmitting data that you won't use. Skipping a large field over a series of requests can yield a noticeable performance improvement.
73
74 {% codeblock as python %}
75 # Get a workflow and output its name and description.
76 # Don't load the workflow definition, which might be large and we're not going to use.
77 workflow = api.workflows().get(
78     uuid='zzzzz-7fd4e-12345abcde67890',
79     select=['name', 'description'],
80 ).execute()
81 print(f"## {workflow['name']} ##\n\n{workflow['description']}")
82
83 # ERROR: This raises a KeyError because we didn't load this field in
84 # the `select` argument.
85 workflow['created_at']
86 {% endcodeblock %}
87
88 h2. list method
89
90 To fetch multiple Arvados objects of the same type, call the @list@ method for that resource type. The list method takes a number of arguments. Refer to the "list method API reference":{{site.baseurl}}/api/methods.html#index for details about them. The method returns a dictionary also documented at the bottom of that section. The most interesting field is @'items'@, which is a list of dictionaries where each one corresponds to an Arvados object that matched your search. To work with a single page of results:
91
92 {% codeblock as python %}
93 # Output the exit codes of the 10 most recently run containers.
94 container_list = arv_client.containers().list(
95     limit=10,
96     order=['finished_at desc'],
97 ).execute()
98 for container in container_list['items']:
99     print(f"{container['uuid']}: {container['exit_code']}")
100 {% endcodeblock %}
101
102 If you need to retrieve all of the results for a query, you may need to call the @list@ method multiple times: the default @limit@ is 100 items, and the API server will never return more than 1000. The SDK function @arvados.util.keyset_list_all@ can help orchestrate this for you. Call it with the @list@ method you want to query (don't call it yourself!) and the same keyword arguments you would pass to that method. You can control ordering by passing an @order_key@ string that names the field to use, and an @ascending@ bool that indicates whether that key should be sorted in ascending or descending order. The function returns an iterator of dictionaries, where each dictionary corresponds to an Arvados object that matched your query.
103
104 {% codeblock as python %}
105 # Output all the portable data hashes in a project.
106 project_data = set()
107 for collection in arvados.util.keyset_list_all(
108     # Note we pass the `list` method without calling it
109     arv_client.collections().list,
110     # The UUID of the project we're searching
111     filters=[['owner_uuid', '=', 'zzzzz-j7d0g-12345abcde67890']],
112 ):
113     project_data.add(collection['portable_data_hash'])
114 print('\n'.join(project_data))
115 {% endcodeblock %}
116
117 When you list many objects, the following can help improve performance:
118
119 * Call the list method with @count='none'@ to avoid the overhead of counting all results with each request.
120 * Call the list method with a @select@ argument to only request the data you need. This cuts out some overhead from de/serializing and transferring data you won't use.
121
122 h2. create method
123
124 To create a new Arvados object, call the @create@ method for that resource type. You must pass a @body@ dictionary with a single item. Its key is the resource type you're creating as a string, and its value is dictionary of data fields for that resource. The method returns a dictionary with the new object's fields.
125
126 If the resource type has a @name@ field, you may pass an @ensure_unique_name@ boolean argument. If true, the method will automatically update the name of the new object to make it unique if necessary.
127
128 {% codeblock as python %}
129 # Create a new project and output its UUID.
130 project = arv_client.groups().create(
131     body={
132         'group': {
133             'name': 'Python SDK Test Project',
134             'group_class': 'project',
135         },
136     },
137     ensure_unique_name=True,
138 ).execute()
139 print(project['uuid'])
140 {% endcodeblock %}
141
142 h2. update method
143
144 To modify an existing Arvados object, call the @update@ method for that resource type. You must pass a @uuid@ string argument that identifies the object to update, and a @body@ dictionary with a single item. Its key is the resource type you're creating as a string, and its value is dictionary of data fields to update on the resource. The method returns a dictionary with the updated object's fields.
145
146 If the resource type has a @name@ field, you may pass an @ensure_unique_name@ boolean argument. If true, the method will automatically update the name of the new object to make it unique if necessary.
147
148 {% codeblock as python %}
149 # Update the name of a container request,
150 # finalize it to submit it to Crunch for processing,
151 # and output its priority.
152 submitted_container_request = arv_client.container_requests().update(
153     uuid='zzzzz-xvhdp-12345abcde67890',
154     body={
155         'container_request': {
156             'name': 'Container Request Committed by Python SDK',
157             'state': 'Committed',
158         },
159     },
160     ensure_unique_name=True,
161 ).execute()
162 print(submitted_container_request['priority'])
163 {% endcodeblock %}
164
165 h2. delete method
166
167 To delete an existing Arvados object, call the @delete@ method for that resource type. You must pass a @uuid@ string argument that identifies the object to delete. The method returns a dictionary with the deleted object's fields.
168
169 {% codeblock as python %}
170 # Delete a collection and output its name
171 deleted_collection = arv_client.collections().delete(
172     uuid='zzzzz-4zz18-12345abcde67890',
173 ).execute()
174 print(deleted_collection['name'])
175 {% endcodeblock %}
176
177 For resource types that support being trashed, you can untrash the object by calling the resource type's @untrash@ method with a @uuid@ argument identifying the object to restore.