1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: Apache-2.0
4 """Thread-safe wrapper for an Arvados API client
6 This module provides `ThreadSafeApiCache`, a thread-safe, API-compatible
10 from __future__ import absolute_import
12 from builtins import object
20 api = sys.modules['arvados.api']
22 class ThreadSafeApiCache(object):
23 """Thread-safe wrapper for an Arvados API client
25 This class takes all the arguments necessary to build a lower-level
26 Arvados API client `googleapiclient.discovery.Resource`, then
27 transparently builds and wraps a unique object per thread. This works
28 around the fact that the client's underlying HTTP client object is not
33 apiconfig: Mapping[str, str] | None
34 : A mapping with entries for `ARVADOS_API_HOST`, `ARVADOS_API_TOKEN`,
35 and optionally `ARVADOS_API_HOST_INSECURE`. If not provided, uses
36 `arvados.config.settings` to get these parameters from user
37 configuration. You can pass an empty mapping to build the client
38 solely from `api_params`.
40 keep_params: Mapping[str, Any]
41 : Keyword arguments used to construct an associated
42 `arvados.keep.KeepClient`.
44 api_params: Mapping[str, Any]
45 : Keyword arguments used to construct each thread's API client. These
46 have the same meaning as in the `arvados.api.api` function.
49 : A string naming the version of the Arvados API to use. If not specified,
50 the code will log a warning and fall back to 'v1'.
53 def __init__(self, apiconfig=None, keep_params={}, api_params={}, version=None):
54 if apiconfig or apiconfig is None:
55 self._api_kwargs = api.api_kwargs_from_config(version, apiconfig, **api_params)
57 self._api_kwargs = api.normalize_api_kwargs(version, **api_params)
58 self.api_token = self._api_kwargs['token']
59 self.request_id = self._api_kwargs.get('request_id')
60 self.local = threading.local()
61 self.keep = keep.KeepClient(api_client=self, **keep_params)
65 client = self.local.api
66 except AttributeError:
67 client = api.api_client(**self._api_kwargs)
68 client._http._request_id = lambda: self.request_id or util.new_request_id()
69 self.local.api = client
72 def __getattr__(self, name):
73 # Proxy nonexistent attributes to the thread-local API client.
74 return getattr(self.localapi(), name)