Skip to content

API reference

dts: a Python client for the Data Transfer Service.

The Data Transfer System (DTS) offers a federated search capability for participating organizations in the DOE Biological and Environmental Research program, and allows the transfer of related data and metadata between these organizations.

DTS API documentation is available here.

Client

dts.Client: A client for performing file transfers with the Data Transfer System (DTS).

This type exposes the DTS API for use in Python programs.

Source code in dts/client.py
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
class Client:
    """`dts.Client`: A client for performing file transfers with the Data Transfer System (DTS).

This type exposes the [DTS API](https://lb-dts.staging.kbase.us/docs#/) for use
in Python programs.
"""
    def __init__(self: "Client",
                 api_key: str | None = None, 
                 server: str | None = None,
                 port: int | None = None) -> None:
        """Creates a DTS client that handles search and transfer requests via
a connected server.

If no server is specified, you must call `connect` on the created client.

Args:
    api_key: An unencoded KBase developer token.
    server: The DTS server that handles the client's API requests.
    port: The port to which the client connects with the server.

Returns:
    a `dts.Client` instance.

Raises:
    TypeError: an argument of improper type was specified.
"""
        if server:
            self.connect(server = server, port = port, api_key = api_key)
        else:
            self.uri = None
            self.name = None
            self.version = None

    def connect(self: "Client",
                api_key: str | None = None,
                server: str | None = None,
                port: int | None = None) -> None:
        """Connects the client to the given DTS server via the given port using the given
(unencoded) KBase developer token.

Args:
    api_key: An unencoded KBase developer token.
    server: The DTS server that handles the client's API requests.
    port: The port to which the client connects with the server.

Raises:
    TypeError: an argument of improper type was specified.
    urllib3.exceptions.ConnectionError: the client was unable to connect to the DTS server.
"""
        if not isinstance(api_key, str):
            raise TypeError('api_key must be an unencoded API key.')
        if not isinstance(server, str):
            raise TypeError('server must be a URI for a DTS server.')
        if port and not isinstance(port, int):
            raise TypeError('port must be an integer')
        self.auth = KBaseAuth(api_key)
        if port:
            server = f'{server}:{port}'

        # perform a root query and fill in some information
        response = requests.get(server, auth = self.auth)
        response.raise_for_status()

        result = response.json()
        self.uri = f'{server}/api/v{api_version}'
        self.name = result['name']
        self.version = result['version']

    def disconnect(self: "Client") -> None:
        """Disconnects the client from the server.
"""
        self.api_key = None
        self.uri = None
        self.name = None
        self.version = None

    def databases(self: "Client") -> list[Database]:
        """Returns all databases available to the service.

Server-side errors are captured and logged.

Returns:
    A list of Database objects containing information about available databases.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        try:
            response = requests.get(self.uri + '/databases', auth = self.auth)
            response.raise_for_status()
        except HTTPError as http_err:
            logger.error(f'HTTP error occurred: {http_err}')
            return []
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return []
        results = response.json()
        return [Database(id = r['id'],
                         name = r['name'],
                         organization = r['organization'],
                         url = r['url']) for r in results]

    def search(self: "Client",
               database: str,
               query: str | int | float,
               status: str | None = None,
               offset: int = 0,
               limit: int | None = None,
               specific: dict[str, Any] | None = None,
    ) -> list[JsonResource]:
        """Performs a synchronous search of the database with the given name using the given query string.

This method searches the indicated database for files that can be transferred.

Args:
    database: A string containing the name of the database to search.
    query: A search string that is directly interpreted by the database.
    status: An optional string (`"staged"` or `"unstaged"`) indicating whether files are filtered based on their status.
    offset: An optional 0-based pagination index indicating the first retrieved result (default: 0).
    limit: An optional pagination parameter indicating the maximum number of results to retrieve.
    specific: An optional dictionary mapping database-specific search parameters to their values.

Returns:
    A list of [frictionless DataResources](https://specs.frictionlessdata.io/data-resource/) containing metadata for files matching the query.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        if not isinstance(query, str):
            # we also accept numeric values
            if isinstance(query, int) or isinstance(query, float):
                query = str(query)
            else:
                raise TypeError('search: query must be a string or a number.')
        if not isinstance(database, str):
            raise TypeError('search: database must be a string.')
        params: dict[str, Any] = {
            'database': database,
            'query':    query,
        }
        if status:
            if status not in ['staged', 'unstaged']:
                raise TypeError(f'search: invalid status: {status}.')
            params['status'] = status
        if offset:
            if not str(offset).isdigit():
                raise TypeError('search: offset must be numeric')
            if int(offset) < 0:
                raise ValueError(f'search: offset must be non-negative')
            params['offset'] = int(offset)
        if limit:
            if not str(limit).isdigit():
                raise TypeError('search: limit must be numeric')
            if int(limit) < 1:
                raise ValueError(f'search: limit must be greater than 1')
            params['limit'] = int(limit)
        if specific:
            if not isinstance(specific, dict):
                raise TypeError('search: specific must be a dict.')
            params['specific'] = specific
        try:
            response = requests.post(url=f'{self.uri}/files',
                                     json=params,
                                     auth=self.auth)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return []
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return []
        return [JsonResource(r) for r in response.json()['resources']]

    def fetch_metadata(self: "Client",
                       database: str,
                       ids: list[str],
                       offset: int = 0,
                       limit: int | None = None) -> list[JsonResource]:
        """Fetches metadata for the files with the specified IDs within the specified database.

Server-side errors are intercepted and logged.

Args:
    database: A string containing the name of the database to search.
    ids: A list containing file identifiers for which metadata is retrieved.
    offset: An optional 0-based pagination index from which to start retrieving results (default: 0).
    limit: An optional pagination parameter indicating the maximum number of results to retrieve.

Returns:
    A list of [frictionless DataResources](https://specs.frictionlessdata.io/data-resource/) containing metadata for files with the requested IDs.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        if not isinstance(ids, list) or len(ids) == 0:
            raise RuntimeError('search: missing or invalid file IDs.')
        if not isinstance(database, str):
            raise TypeError('search: database must be a string.')
        params: dict[str, Any] = {
            'database': database,
            'ids':    ','.join(ids),
        }
        if offset:
            if not str(offset).isdigit():
                raise TypeError('search: offset must be numeric')
            if int(offset) < 0:
                raise ValueError(f'search: offset must be non-negative')
            params['offset'] = int(offset)
        if limit:
            if not str(limit).isdigit():
                raise TypeError('search: limit must be numeric')
            if int(limit) < 1:
                raise ValueError(f'search: limit must be greater than 1')
            params['limit'] = int(limit)
        try:
            response = requests.get(url=f'{self.uri}/files/by-id',
                                    params=params,
                                    auth=self.auth)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return []
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return []
        return [JsonResource(r) for r in response.json()['resources']]

    def transfer(self: "Client",
                 file_ids: list[str],
                 source: str,
                 destination: str,
                 description: str | None = None,
                 instructions: dict[str, Any] | None = None,
                 timeout: int | None = None) -> uuid.UUID | None:
        """Submits a request to transfer files from a source to a destination database.

Server-side errors are intercepted and logged.

Args:
    file_ids: A list of identifiers for files to be transferred.
    source: The name of the database from which files are transferred.
    destination: The name of the database to which files are transferred.
    description: An optional string containing human-readable Markdown text describing the transfer.
    instructions: An optional dict representing a JSON object containing instructions for processing the payload at its destination.
    timeout: An optional integer indicating the number of seconds to wait for a response from the server.

Returns:
    A UUID uniquely identifying the file transfer that can be used to check its status, or None if a server-side error is encountered.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        if not isinstance(source, str):
            raise TypeError('transfer: source database name must be a string.')
        if not isinstance(destination, str):
            raise TypeError('transfer: destination database name must be a string.')
        if not isinstance(file_ids, list):
            raise TypeError('transfer: file_ids must be a list of string file IDs.')
        if timeout and not isinstance(timeout, int) and not isinstance(timeout, float):
            raise TypeError('transfer: timeout must be a number of seconds.')
        if description and not isinstance(description, str):
            raise TypeError('transfer: description must be a string containing Markdown.')
        if instructions and not isinstance(instructions, dict):
            raise TypeError('transfer: instructions must be a dict representing a JSON object containing machine-readable instructions for processing the payload at its destination.')
        json_obj = {
            'source':      source,
            'destination': destination,
            'file_ids':    file_ids,
        }
        if description:
            json_obj['description'] = description
        if instructions:
            json_obj['instructions'] = instructions
        try:
            response = requests.post(url=f'{self.uri}/transfers',
                                     json=json_obj,
                                     auth=self.auth,
                                     timeout=timeout)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return None
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return None
        return uuid.UUID(response.json()["id"])

    def transfer_status(self: "Client",
                        id: uuid.UUID) -> TransferStatus | None:
        """Returns status information for the transfer with the given identifier.


Server-side errors are intercepted and logged. Possible transfer statuses are:

* `'staging'`: The files requested for transfer are being copied to the staging
               area for the source database job.
* `'active'`: The files are being transferred from the source database to the 
              destination database.
* `'finalizing'`: The files have been transferred and a manifest is being written.
* `'inactive'`: The file transfer has been suspended.
* `'failed'`: The file transfer could not be completed because of a failure.
* `'unknown'`: The status of the given transfer is unknown.

Arguments:
    id: A UUID that uniquely identifies the transfer operation for which the status is requested.

Returns:
    A `TransferStatus` object whose contents indicate the status of the transfer, or None if a server-side error occurs.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        try:
            response = requests.get(url=f'{self.uri}/transfers/{id}',
                                    auth=self.auth)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return None
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return None
        results = response.json()
        return TransferStatus(
            id                    = results.get('id'),
            status                = results.get('status'),
            message               = results.get('message'),
            num_files             = results.get('num_files'),
            num_files_transferred = results.get('num_files_transferred'),
        )

    def cancel_transfer(self: "Client",
                        id: uuid.UUID) -> None:
        """Cancels a file transfer with the requested UUID.

Status information for the cancelled transfer is retained for a time so its
cancellation can be seen.

Args:
    id: A UUID that uniquely identifies the transfer operation to be cancelled.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        try:
            response = requests.delete(url=f'{self.uri}/transfers/{id}',
                                       auth=self.auth)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return None
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return None
        return None

    def __repr__(self: "Client") -> str:
        if self.uri:
            return f"""
dts.Client(uri     = {self.uri},
           name    = {self.name},
           version = {self.version} """
        else:
            return "dts.Client(disconnected)"

__init__(api_key=None, server=None, port=None)

Creates a DTS client that handles search and transfer requests via a connected server.

If no server is specified, you must call connect on the created client.

Parameters:

Name Type Description Default
api_key str | None

An unencoded KBase developer token.

None
server str | None

The DTS server that handles the client's API requests.

None
port int | None

The port to which the client connects with the server.

None

Returns:

Type Description
None

a dts.Client instance.

Raises:

Type Description
TypeError

an argument of improper type was specified.

Source code in dts/client.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    def __init__(self: "Client",
                 api_key: str | None = None, 
                 server: str | None = None,
                 port: int | None = None) -> None:
        """Creates a DTS client that handles search and transfer requests via
a connected server.

If no server is specified, you must call `connect` on the created client.

Args:
    api_key: An unencoded KBase developer token.
    server: The DTS server that handles the client's API requests.
    port: The port to which the client connects with the server.

Returns:
    a `dts.Client` instance.

Raises:
    TypeError: an argument of improper type was specified.
"""
        if server:
            self.connect(server = server, port = port, api_key = api_key)
        else:
            self.uri = None
            self.name = None
            self.version = None

cancel_transfer(id)

Cancels a file transfer with the requested UUID.

Status information for the cancelled transfer is retained for a time so its cancellation can be seen.

Parameters:

Name Type Description Default
id UUID

A UUID that uniquely identifies the transfer operation to be cancelled.

required

Raises:

Type Description
RuntimeError

Indicates an issue with the DTS client and its connection to the server.

TypeError

Indicates that an argument passed to the client isn't of the proper type.

ValueError

Indicates that an argument passed to the client has an invalid value.

Source code in dts/client.py
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
    def cancel_transfer(self: "Client",
                        id: uuid.UUID) -> None:
        """Cancels a file transfer with the requested UUID.

Status information for the cancelled transfer is retained for a time so its
cancellation can be seen.

Args:
    id: A UUID that uniquely identifies the transfer operation to be cancelled.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        try:
            response = requests.delete(url=f'{self.uri}/transfers/{id}',
                                       auth=self.auth)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return None
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return None
        return None

connect(api_key=None, server=None, port=None)

Connects the client to the given DTS server via the given port using the given (unencoded) KBase developer token.

Parameters:

Name Type Description Default
api_key str | None

An unencoded KBase developer token.

None
server str | None

The DTS server that handles the client's API requests.

None
port int | None

The port to which the client connects with the server.

None

Raises:

Type Description
TypeError

an argument of improper type was specified.

ConnectionError

the client was unable to connect to the DTS server.

Source code in dts/client.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
    def connect(self: "Client",
                api_key: str | None = None,
                server: str | None = None,
                port: int | None = None) -> None:
        """Connects the client to the given DTS server via the given port using the given
(unencoded) KBase developer token.

Args:
    api_key: An unencoded KBase developer token.
    server: The DTS server that handles the client's API requests.
    port: The port to which the client connects with the server.

Raises:
    TypeError: an argument of improper type was specified.
    urllib3.exceptions.ConnectionError: the client was unable to connect to the DTS server.
"""
        if not isinstance(api_key, str):
            raise TypeError('api_key must be an unencoded API key.')
        if not isinstance(server, str):
            raise TypeError('server must be a URI for a DTS server.')
        if port and not isinstance(port, int):
            raise TypeError('port must be an integer')
        self.auth = KBaseAuth(api_key)
        if port:
            server = f'{server}:{port}'

        # perform a root query and fill in some information
        response = requests.get(server, auth = self.auth)
        response.raise_for_status()

        result = response.json()
        self.uri = f'{server}/api/v{api_version}'
        self.name = result['name']
        self.version = result['version']

databases()

Returns all databases available to the service.

Server-side errors are captured and logged.

Returns:

Type Description
list[Database]

A list of Database objects containing information about available databases.

Source code in dts/client.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    def databases(self: "Client") -> list[Database]:
        """Returns all databases available to the service.

Server-side errors are captured and logged.

Returns:
    A list of Database objects containing information about available databases.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        try:
            response = requests.get(self.uri + '/databases', auth = self.auth)
            response.raise_for_status()
        except HTTPError as http_err:
            logger.error(f'HTTP error occurred: {http_err}')
            return []
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return []
        results = response.json()
        return [Database(id = r['id'],
                         name = r['name'],
                         organization = r['organization'],
                         url = r['url']) for r in results]

disconnect()

Disconnects the client from the server.

Source code in dts/client.py
 98
 99
100
101
102
103
104
    def disconnect(self: "Client") -> None:
        """Disconnects the client from the server.
"""
        self.api_key = None
        self.uri = None
        self.name = None
        self.version = None

fetch_metadata(database, ids, offset=0, limit=None)

Fetches metadata for the files with the specified IDs within the specified database.

Server-side errors are intercepted and logged.

Parameters:

Name Type Description Default
database str

A string containing the name of the database to search.

required
ids list[str]

A list containing file identifiers for which metadata is retrieved.

required
offset int

An optional 0-based pagination index from which to start retrieving results (default: 0).

0
limit int | None

An optional pagination parameter indicating the maximum number of results to retrieve.

None

Returns:

Type Description
list[JsonResource]

A list of frictionless DataResources containing metadata for files with the requested IDs.

Raises:

Type Description
RuntimeError

Indicates an issue with the DTS client and its connection to the server.

TypeError

Indicates that an argument passed to the client isn't of the proper type.

ValueError

Indicates that an argument passed to the client has an invalid value.

Source code in dts/client.py
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    def fetch_metadata(self: "Client",
                       database: str,
                       ids: list[str],
                       offset: int = 0,
                       limit: int | None = None) -> list[JsonResource]:
        """Fetches metadata for the files with the specified IDs within the specified database.

Server-side errors are intercepted and logged.

Args:
    database: A string containing the name of the database to search.
    ids: A list containing file identifiers for which metadata is retrieved.
    offset: An optional 0-based pagination index from which to start retrieving results (default: 0).
    limit: An optional pagination parameter indicating the maximum number of results to retrieve.

Returns:
    A list of [frictionless DataResources](https://specs.frictionlessdata.io/data-resource/) containing metadata for files with the requested IDs.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        if not isinstance(ids, list) or len(ids) == 0:
            raise RuntimeError('search: missing or invalid file IDs.')
        if not isinstance(database, str):
            raise TypeError('search: database must be a string.')
        params: dict[str, Any] = {
            'database': database,
            'ids':    ','.join(ids),
        }
        if offset:
            if not str(offset).isdigit():
                raise TypeError('search: offset must be numeric')
            if int(offset) < 0:
                raise ValueError(f'search: offset must be non-negative')
            params['offset'] = int(offset)
        if limit:
            if not str(limit).isdigit():
                raise TypeError('search: limit must be numeric')
            if int(limit) < 1:
                raise ValueError(f'search: limit must be greater than 1')
            params['limit'] = int(limit)
        try:
            response = requests.get(url=f'{self.uri}/files/by-id',
                                    params=params,
                                    auth=self.auth)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return []
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return []
        return [JsonResource(r) for r in response.json()['resources']]

search(database, query, status=None, offset=0, limit=None, specific=None)

Performs a synchronous search of the database with the given name using the given query string.

This method searches the indicated database for files that can be transferred.

Parameters:

Name Type Description Default
database str

A string containing the name of the database to search.

required
query str | int | float

A search string that is directly interpreted by the database.

required
status str | None

An optional string ("staged" or "unstaged") indicating whether files are filtered based on their status.

None
offset int

An optional 0-based pagination index indicating the first retrieved result (default: 0).

0
limit int | None

An optional pagination parameter indicating the maximum number of results to retrieve.

None
specific dict[str, Any] | None

An optional dictionary mapping database-specific search parameters to their values.

None

Returns:

Type Description
list[JsonResource]

A list of frictionless DataResources containing metadata for files matching the query.

Raises:

Type Description
RuntimeError

Indicates an issue with the DTS client and its connection to the server.

TypeError

Indicates that an argument passed to the client isn't of the proper type.

ValueError

Indicates that an argument passed to the client has an invalid value.

Source code in dts/client.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
    def search(self: "Client",
               database: str,
               query: str | int | float,
               status: str | None = None,
               offset: int = 0,
               limit: int | None = None,
               specific: dict[str, Any] | None = None,
    ) -> list[JsonResource]:
        """Performs a synchronous search of the database with the given name using the given query string.

This method searches the indicated database for files that can be transferred.

Args:
    database: A string containing the name of the database to search.
    query: A search string that is directly interpreted by the database.
    status: An optional string (`"staged"` or `"unstaged"`) indicating whether files are filtered based on their status.
    offset: An optional 0-based pagination index indicating the first retrieved result (default: 0).
    limit: An optional pagination parameter indicating the maximum number of results to retrieve.
    specific: An optional dictionary mapping database-specific search parameters to their values.

Returns:
    A list of [frictionless DataResources](https://specs.frictionlessdata.io/data-resource/) containing metadata for files matching the query.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        if not isinstance(query, str):
            # we also accept numeric values
            if isinstance(query, int) or isinstance(query, float):
                query = str(query)
            else:
                raise TypeError('search: query must be a string or a number.')
        if not isinstance(database, str):
            raise TypeError('search: database must be a string.')
        params: dict[str, Any] = {
            'database': database,
            'query':    query,
        }
        if status:
            if status not in ['staged', 'unstaged']:
                raise TypeError(f'search: invalid status: {status}.')
            params['status'] = status
        if offset:
            if not str(offset).isdigit():
                raise TypeError('search: offset must be numeric')
            if int(offset) < 0:
                raise ValueError(f'search: offset must be non-negative')
            params['offset'] = int(offset)
        if limit:
            if not str(limit).isdigit():
                raise TypeError('search: limit must be numeric')
            if int(limit) < 1:
                raise ValueError(f'search: limit must be greater than 1')
            params['limit'] = int(limit)
        if specific:
            if not isinstance(specific, dict):
                raise TypeError('search: specific must be a dict.')
            params['specific'] = specific
        try:
            response = requests.post(url=f'{self.uri}/files',
                                     json=params,
                                     auth=self.auth)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return []
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return []
        return [JsonResource(r) for r in response.json()['resources']]

transfer(file_ids, source, destination, description=None, instructions=None, timeout=None)

Submits a request to transfer files from a source to a destination database.

Server-side errors are intercepted and logged.

Parameters:

Name Type Description Default
file_ids list[str]

A list of identifiers for files to be transferred.

required
source str

The name of the database from which files are transferred.

required
destination str

The name of the database to which files are transferred.

required
description str | None

An optional string containing human-readable Markdown text describing the transfer.

None
instructions dict[str, Any] | None

An optional dict representing a JSON object containing instructions for processing the payload at its destination.

None
timeout int | None

An optional integer indicating the number of seconds to wait for a response from the server.

None

Returns:

Type Description
UUID | None

A UUID uniquely identifying the file transfer that can be used to check its status, or None if a server-side error is encountered.

Raises:

Type Description
RuntimeError

Indicates an issue with the DTS client and its connection to the server.

TypeError

Indicates that an argument passed to the client isn't of the proper type.

ValueError

Indicates that an argument passed to the client has an invalid value.

Source code in dts/client.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
    def transfer(self: "Client",
                 file_ids: list[str],
                 source: str,
                 destination: str,
                 description: str | None = None,
                 instructions: dict[str, Any] | None = None,
                 timeout: int | None = None) -> uuid.UUID | None:
        """Submits a request to transfer files from a source to a destination database.

Server-side errors are intercepted and logged.

Args:
    file_ids: A list of identifiers for files to be transferred.
    source: The name of the database from which files are transferred.
    destination: The name of the database to which files are transferred.
    description: An optional string containing human-readable Markdown text describing the transfer.
    instructions: An optional dict representing a JSON object containing instructions for processing the payload at its destination.
    timeout: An optional integer indicating the number of seconds to wait for a response from the server.

Returns:
    A UUID uniquely identifying the file transfer that can be used to check its status, or None if a server-side error is encountered.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        if not isinstance(source, str):
            raise TypeError('transfer: source database name must be a string.')
        if not isinstance(destination, str):
            raise TypeError('transfer: destination database name must be a string.')
        if not isinstance(file_ids, list):
            raise TypeError('transfer: file_ids must be a list of string file IDs.')
        if timeout and not isinstance(timeout, int) and not isinstance(timeout, float):
            raise TypeError('transfer: timeout must be a number of seconds.')
        if description and not isinstance(description, str):
            raise TypeError('transfer: description must be a string containing Markdown.')
        if instructions and not isinstance(instructions, dict):
            raise TypeError('transfer: instructions must be a dict representing a JSON object containing machine-readable instructions for processing the payload at its destination.')
        json_obj = {
            'source':      source,
            'destination': destination,
            'file_ids':    file_ids,
        }
        if description:
            json_obj['description'] = description
        if instructions:
            json_obj['instructions'] = instructions
        try:
            response = requests.post(url=f'{self.uri}/transfers',
                                     json=json_obj,
                                     auth=self.auth,
                                     timeout=timeout)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return None
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return None
        return uuid.UUID(response.json()["id"])

transfer_status(id)

Returns status information for the transfer with the given identifier.

Server-side errors are intercepted and logged. Possible transfer statuses are:

  • 'staging': The files requested for transfer are being copied to the staging area for the source database job.
  • 'active': The files are being transferred from the source database to the destination database.
  • 'finalizing': The files have been transferred and a manifest is being written.
  • 'inactive': The file transfer has been suspended.
  • 'failed': The file transfer could not be completed because of a failure.
  • 'unknown': The status of the given transfer is unknown.

Parameters:

Name Type Description Default
id UUID

A UUID that uniquely identifies the transfer operation for which the status is requested.

required

Returns:

Type Description
TransferStatus | None

A TransferStatus object whose contents indicate the status of the transfer, or None if a server-side error occurs.

Raises:

Type Description
RuntimeError

Indicates an issue with the DTS client and its connection to the server.

TypeError

Indicates that an argument passed to the client isn't of the proper type.

ValueError

Indicates that an argument passed to the client has an invalid value.

Source code in dts/client.py
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
    def transfer_status(self: "Client",
                        id: uuid.UUID) -> TransferStatus | None:
        """Returns status information for the transfer with the given identifier.


Server-side errors are intercepted and logged. Possible transfer statuses are:

* `'staging'`: The files requested for transfer are being copied to the staging
               area for the source database job.
* `'active'`: The files are being transferred from the source database to the 
              destination database.
* `'finalizing'`: The files have been transferred and a manifest is being written.
* `'inactive'`: The file transfer has been suspended.
* `'failed'`: The file transfer could not be completed because of a failure.
* `'unknown'`: The status of the given transfer is unknown.

Arguments:
    id: A UUID that uniquely identifies the transfer operation for which the status is requested.

Returns:
    A `TransferStatus` object whose contents indicate the status of the transfer, or None if a server-side error occurs.

Raises:
    RuntimeError: Indicates an issue with the DTS client and its connection to the server.
    TypeError: Indicates that an argument passed to the client isn't of the proper type.
    ValueError: Indicates that an argument passed to the client has an invalid value.
"""
        if not self.uri:
            raise RuntimeError('dts.Client: not connected.')
        try:
            response = requests.get(url=f'{self.uri}/transfers/{id}',
                                    auth=self.auth)
            response.raise_for_status()
        except (HTTPError, requests.exceptions.HTTPError) as err:
            logger.error(f'HTTP error occurred: {err}')
            return None
        except Exception as err:
            logger.error(f'Other error occurred: {err}')
            return None
        results = response.json()
        return TransferStatus(
            id                    = results.get('id'),
            status                = results.get('status'),
            message               = results.get('message'),
            num_files             = results.get('num_files'),
            num_files_transferred = results.get('num_files_transferred'),
        )

Database dataclass

Database - A database storing files that can be selected and transferred.

This type holds human-readable information about databases available to DTS. Objects of this type are returned by calls to the DTS API, so it is not necessary to construct them directly.

Source code in dts/database.py
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@dataclass(slots = True)
class Database:
    """`Database` - A database storing files that can be selected and transferred.

This type holds human-readable information about databases available to DTS.
Objects of this type are returned by calls to the DTS API, so it is not
necessary to construct them directly.
"""
    id:   str
    name: str
    organization: str
    url: str

TransferStatus dataclass

TransferStatus status information for a file transfer.

This type holds information pertaining to the transfer of a payload initiated via the DTS. Objects of this type are returned by calls to the DTS API, so it is not necessary to create them directly.

Source code in dts/transfer_status.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@dataclass(slots = True)
class TransferStatus:
    """`TransferStatus` status information for a file transfer.

This type holds information pertaining to the transfer of a payload initiated
via the DTS. Objects of this type are returned by calls to the DTS API, so it
is not necessary to create them directly.
"""
    id:                    str
    status:                str
    message:               Optional[str]
    num_files:             int
    num_files_transferred: int