github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/clients/python-wrapper/lakefs/client.py (about)

     1  """
     2  lakeFS Client module
     3  
     4  Handles authentication against the lakeFS server and wraps the underlying lakefs_sdk client.
     5  """
     6  
     7  from __future__ import annotations
     8  
     9  from typing import Optional
    10  from threading import Lock
    11  
    12  import lakefs_sdk
    13  from lakefs_sdk.client import LakeFSClient
    14  
    15  from lakefs.config import ClientConfig
    16  from lakefs.exceptions import NotAuthorizedException, ServerException, api_exception_handler
    17  from lakefs.models import ServerStorageConfiguration
    18  
    19  
    20  class ServerConfiguration:
    21      """
    22      Represent a lakeFS server's configuration
    23      """
    24      _conf: lakefs_sdk.Config
    25      _storage_conf: ServerStorageConfiguration
    26  
    27      def __init__(self, client: Optional[Client] = None):
    28          try:
    29              self._conf = client.sdk_client.config_api.get_config()
    30              self._storage_conf = ServerStorageConfiguration(**self._conf.storage_config.dict())
    31          except lakefs_sdk.exceptions.ApiException as e:
    32              if isinstance(e, lakefs_sdk.exceptions.ApiException):
    33                  raise NotAuthorizedException(e.status, e.reason) from e
    34              raise ServerException(e.status, e.reason) from e
    35  
    36      @property
    37      def version(self) -> str:
    38          """
    39          Return the lakeFS server version
    40          """
    41          return self._conf.version_config.version
    42  
    43      @property
    44      def storage_config(self) -> ServerStorageConfiguration:
    45          """
    46          Returns the lakeFS server storage configuration
    47          """
    48          return self._storage_conf
    49  
    50  
    51  class Client:
    52      """
    53      Wrapper around lakefs_sdk's client object
    54      Takes care of instantiating it from the environment
    55  
    56      Example of initializing a Client object:
    57  
    58      .. code-block:: python
    59  
    60          from lakefs import Client
    61  
    62          client = Client(username="<access_key_id>", password="<secret_access_key>", host="<lakefs_endpoint>")
    63          print(client.version)
    64  
    65      """
    66  
    67      _client: Optional[LakeFSClient] = None
    68      _conf: Optional[ClientConfig] = None
    69      _server_conf: Optional[ServerConfiguration] = None
    70  
    71      def __init__(self, **kwargs):
    72          self._conf = ClientConfig(**kwargs)
    73          self._client = LakeFSClient(self._conf, header_name='X-Lakefs-Client',
    74                                      header_value='python-lakefs')
    75  
    76      @property
    77      def config(self):
    78          """
    79          Return the underlying lakefs_sdk configuration
    80          """
    81          return self._conf
    82  
    83      @property
    84      def sdk_client(self):
    85          """
    86          Return the underlying lakefs_sdk client
    87          """
    88          return self._client
    89  
    90      @property
    91      def storage_config(self):
    92          """
    93          lakeFS SDK storage config object, lazy evaluated.
    94          """
    95          if self._server_conf is None:
    96              self._server_conf = ServerConfiguration(self)
    97          return self._server_conf.storage_config
    98  
    99      @property
   100      def version(self) -> str:
   101          """
   102          lakeFS Server version, lazy evaluated.
   103          """
   104          if self._server_conf is None:
   105              self._server_conf = ServerConfiguration(self)
   106          return self._server_conf.version
   107  
   108  
   109  def from_web_identity(code: str, state: str, redirect_uri: str, ttl_seconds: int = 3600, **kwargs) -> Client:
   110      """
   111      Authenticate against lakeFS using a code received from an identity provider
   112  
   113      :param code: The code received from the identity provider
   114      :param state: The state received from the identity provider
   115      :param redirect_uri: The redirect URI used in the authentication process
   116      :param ttl_seconds: The token's time-to-live in seconds
   117      :param kwargs: Remaining arguments for the Client object
   118      :return: The authenticated Client object
   119      :raise NotAuthorizedException: if user is not authorized to perform this operation
   120      """
   121      client = Client(**kwargs)
   122      sts_requests = lakefs_sdk.StsAuthRequest(code=code, state=state, redirect_uri=redirect_uri, ttl_seconds=ttl_seconds)
   123      with api_exception_handler():
   124          auth_token = client.sdk_client.experimental_api.sts_login(sts_requests)
   125      client.config.access_token = auth_token.token
   126      return client
   127  
   128  
   129  class _BaseLakeFSObject:
   130      """
   131      Base class for all lakeFS SDK objects, holds the client object and handles errors where no authentication method
   132      found for client. Attempts to reload client dynamically in case of changes in the environment.
   133      """
   134      __mutex: Lock = Lock()
   135      __client: Optional[Client] = None
   136  
   137      def __init__(self, client: Optional[Client]):
   138          self.__client = client
   139  
   140      @property
   141      def _client(self):
   142          """
   143          If client is None due to missing authentication params, try to init again. If authentication method is still
   144          missing - will raise exception
   145          :return: The initialized client object
   146          :raise NoAuthenticationFound: If no authentication method found to configure the lakeFS client with
   147          """
   148          if self.__client is not None:
   149              return self.__client
   150  
   151          with _BaseLakeFSObject.__mutex:
   152              if _BaseLakeFSObject.__client is None:
   153                  _BaseLakeFSObject.__client = Client()
   154              return _BaseLakeFSObject.__client