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 utilitiesNote 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
mainbranch may not always correspond to the latest REST API version.If you install
finbourne-sdk-utils, the version number of this package must be1.0.0or 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 # ModelsAuthentication
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:
The
FBN_PROFILEenvironment variable, if set.The
profile_nameparameter when you instantiate the SDK, if specified (see below).The
defaultprofile.
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_URLandFBN_WORKFLOW_API_URLwithFBN_BASE_URL, and point to the root of your domain (without an/apisuffix).If using a secrets file, make sure the JSON document matches the new profile specification. Also replace per-application keys such as
lusidUrlandworkflowUrlwithbaseUrl, and point to the root of your domain (without an/apisuffix).If using the asynchronous SDK, call dedicated
*_async()methods such aslist_instruments_async()instead oflist_instruments().
Appendix B: Environment variable reference
| Root of the LUSID domain to connect to |
| Okta token URL for OAuth2 flow |
| LUSID user name for OAuth2 flow |
| LUSID user password for OAuth2 flow |
| Client ID for OAuth2 flow |
| Client secret for OAuth2 flow |
| Personal access token (less secure than OAuth2) |
| Application name header |
| Sets the active profile in a |
| Total timeout configuration option |
| Authentication timeout configuration option |
| Read timeout configuration option |
| Rate limit retries configuration option |