Installing or upgrading to the v3 Python SDK

Prev Next

Important: This is the latest version. Information about older versions can be found here.

The v3 Python SDK is a universal SDK that provides access to LUSID and to all the other applications in the FINBOURNE platform in a single package.

You no longer need to install and authenticate to separate SDKs to integrate LUSID with applications such as Drive, Workflow Service, Luminesce and so on.

Installation

To get started, install the universal SDK from PyPi using your preferred package manager, for example pip:

pip install finbourne-sdk
pip install finbourne-sdk-utils         # Optional useful utilities

Note the following:

  • Python 3.11 or later is required.

  • We recommend pinning the SDK to an exact version to control when you take updates and make your builds repeatable. Note this is a new package, so the version number starts at 0.0.1.

  • Alternatively, you can download the source by cloning the Github repo. If you do, note the main branch may not always correspond to the latest REST API version.

  • If you install finbourne-sdk-utils, the version number of this package must be 1.0.0 or later.

Import statements

Import endpoints and models for all the FINBOURNE applications you intend to use from finbourne.sdk.services:

# General imports:
import finbourne.sdk.extensions as fbn              # Required
import finbourne.sdk.exceptions as fbn_error        # For error handling
import finbourne_sdk_utils as fbn_utils             # If installed
import asyncio                                      # Required for asynchronous SDK

# To use LUSID:
import finbourne.sdk.services.lusid.api as la       # Endpoints
import finbourne.sdk.services.lusid.models as lm    # Models

# To use the Workflow Service:
import finbourne.sdk.services.workflow as wa        # Endpoints
import finbourne.sdk.services.workflow as wm        # Models

Authentication

The most secure method is OAuth2. If you haven’t already, create a SDK application encapsulating a client ID, secret and token URL, and store them with the credentials of a valid LUSID user as either environment variables or in a secrets file. The SDK uses these credentials to obtain a short-lived access token from FINBOURNE's identity provider (Okta) on demand, which it can then refresh periodically.

Note: If environment variables are set, they are preferred over a secrets file. More information.

You can use a long-lived personal access token (PAT) instead of OAuth2, but note this is less secure.

Using environment variables

All applications share a FBN_BASE_URL pointing to the root of your LUSID domain, for example acme-prod.lusid.com:

# OAuth2 (more secure):
export FBN_BASE_URL = "https://acme-prod.lusid.com"                                   # Root of your FBN domain
export FBN_TOKEN_URL = "https://acme-prod.identity.lusid.com/oauth2/.../v1/token"     # Okta token endpoint
export FBN_USERNAME = "..."
export FBN_PASSWORD = "..."
export FBN_CLIENT_ID = "..."
export FBN_CLIENT_SECRET = "..."

# PAT:
export FBN_BASE_URL = "https://acme-prod.lusid.com"
export FBN_ACCESS_TOKEN = "..."

Using a secrets file

A secrets file is a JSON document with profiles, one per LUSID domain you wish to connect to. Note the file must have at least one default profile. You can switch between profiles to connect to different domains dynamically.

The following example has two profiles: default connects to an acme-prod.lusid.com domain (authenticating using OAuth2) and a second staging profile connects to an acme-sit.lusid.com domain (authenticating using a PAT):

{
  "profiles": {
    "default": {
      "baseUrl": "https://acme-prod.lusid.com/",
      "tokenUrl": "https://acme-prod.identity.lusid.com/oauth2/.../v1/token",
      "username": "...",
      "password": "...",
      "clientId": "...",
      "clientSecret": "..."
    },
    "staging": {
      "baseUrl": "https://acme-sit.lusid.com",
      "accessToken": "..."
    }
  }
}

The active profile is determined in the following order:

  1. The FBN_PROFILE environment variable, if set.

  2. The profile_name parameter when you instantiate the SDK, if specified (see below).

  3. The default profile.

Instantiation

If you are using environment variables you can omit the secrets_path parameter.

If you are using a secrets file you have the option to specify the profile_name parameter to connect to a particular LUSID domain dynamically.

If you are using OAuth2 we recommend specifying the access_token parameter to refresh the short-lived token automatically upon expiry. More configuration options.

Synchronous SDK

Use finbourne.sdk.extensions.SyncApiClientFactory():

api_factory = fbn.SyncApiClientFactory(
  secrets_path = "/path/to/secrets.json", 
  profile_name = "staging",
  access_token = fbn.RefreshingToken()
)

# Build APIs you intend to use:
instruments_api = api_factory.build(la.InstrumentsApi)
workflow_task_definitions_api = api_factory.build(wa.TaskDefinitionsApi)

# Call methods:
list_instr_response = instruments_api.list_instruments()

Asynchronous SDK

The SDK now has full asynchronous support with dedicated *_async() methods, for example list_instruments_async().

Note the precise way to call these methods depends on your environment. For example, if running inside a Jupyter Notebook there is no need to start an event loop. However, if running a Python script at the command line, you must start an event loop using asyncio.run().

Use finbourne.sdk.extensions.ApiClientFactory():

# Jupyter Notebook:
async with fbn.ApiClientFactory(secrets_path = "/path/to/secrets.json") as async_api_factory:
    # Build APIs you intend to use:
    instruments_api = async_api_factory.build(la.InstrumentsApi)
    workflow_task_definitions_api = async_api_factory.build(wa.TaskDefinitionsApi)
    # Call methods directly:
    list_instr_response = await instruments_api.list_instruments_async()

# Python script:
async with fbn.ApiClientFactory(secrets_path = "/path/to/secrets.json") as async_api_factory:
    # Build APIs you intend to use:
    instruments_api = async_api_factory.build(la.InstrumentsApi)
    workflow_task_definitions_api = async_api_factory.build(wa.TaskDefinitionsApi)
# Call methods inside a runnable function:
async def list_instrs():
    list_instr_response = await instruments_api.list_instruments_async()
asyncio.run(list_instrs())

Configuration

You can optionally configure the following settings using the opts parameter:

my_options = fbn.ConfigurationOptions(
    total_timeout_ms = 9999,       # Default is 1800000 (30 minutes)
    connect_timeout_ms = 8888,     # Default is 0 (no timeout)
    read_timeout_ms = 7777,        # Default is 0 (no timeout)
    rate_limit_retries = 50        # Default is 2
)
api_factory = fbn.SyncApiClientFactory(opts = my_options)

Note you can also set these as environment variables, but the opts parameter is preferred if you do both.

You can specify these settings per API call if you wish, for example:

my_option = fbn.ConfigurationOptions(total_timeout_ms = 6666)
list_instr_response = instruments_api.list_instruments(opts = my_option)

Hello world

The following example authenticates to the synchronous SDK using a secrets file and calls the list_instruments() method to invoke the ListInstruments API, formatting the response as a DataFrame:

# Setup:
import finbourne.sdk.extensions as fbn
import finbourne.sdk.exceptions as fbn_error
import finbourne_sdk_utils as fbn_utils
import finbourne.sdk.services.lusid.api as la
import finbourne.sdk.services.lusid.models as lm

# Instantiate and authenticate:
api_factory = fbn.SyncApiClientFactory(secrets_path = "secrets.json")

# Build Instruments API and list first five instruments:
try:
    instruments_api = api_factory.build(la.InstrumentsApi)
    list_instrs_response = instruments_api.list_instruments(limit = 5)
    print(fbn_utils.pandas_utils.lusid_response_to_data_frame(list_instrs_response)[["name", "lusidInstrumentId", "assetClass"]])
except fbn_error.ApiException as e:
    print(e)

For more information on FINBOURNE APIs, start with the articles in this KB, our API sandbox, and library of Jupyter Notebooks.

Appendix A: Migration checklist

If you are upgrading from v2:

  • If using environment variables, replace per-application variables such as FBN_LUSID_API_URL and FBN_WORKFLOW_API_URL with FBN_BASE_URL, and point to the root of your domain (without an /api suffix).

  • If using a secrets file, make sure the JSON document matches the new profile specification. Also replace per-application keys such as lusidUrl and workflowUrl with baseUrl, and point to the root of your domain (without an /api suffix).

  • If using the asynchronous SDK, call dedicated *_async() methods such as list_instruments_async() instead of list_instruments().

Appendix B: Environment variable reference

FBN_BASE_URL

Root of the LUSID domain to connect to

FBN_TOKEN_URL

Okta token URL for OAuth2 flow

FBN_USERNAME

LUSID user name for OAuth2 flow

FBN_PASSWORD

LUSID user password for OAuth2 flow

FBN_CLIENT_ID

Client ID for OAuth2 flow

FBN_CLIENT_SECRET

Client secret for OAuth2 flow

FBN_ACCESS_TOKEN

Personal access token (less secure than OAuth2)

FBN_APP_NAME

Application name header

FBN_PROFILE

Sets the active profile in a secrets.json file

FBN_TOTAL_TIMEOUT_MS

Total timeout configuration option

FBN_CONNECT_TIMEOUT_MS

Authentication timeout configuration option

FBN_READ_TIMEOUT_MS

Read timeout configuration option

FBN_RATE_LIMIT_RETRIES

Rate limit retries configuration option