liminal-sdk-python


Nameliminal-sdk-python JSON
Version 2024.4.3 PyPI version JSON
download
home_pagehttps://github.com/liminal-ai-security/liminal-sdk-python
SummaryThe Liminal SDK for Python
upload_time2024-04-12 05:10:36
maintainerNone
docs_urlNone
authorAaron Bach
requires_python<4.0.0,>=3.11.8
licenseApache-2.0
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Liminal Python SDK

[![CI][ci-badge]][ci]
[![PyPI][pypi-badge]][pypi]
[![Version][version-badge]][version]
[![License][license-badge]][license]

The Liminal SDK for Python provides a clean, straightforward, `asyncio`-based interface
for interacting with the Liminal API.

- [Installation](#installation)
- [Python Versions](#python-versions)
- [Quickstart](#quickstart)
- [Initial Authentication](#initial-authentication)
  - [Microsoft Entra ID](#microsoft-entra-id)
    - [Device Code Flow](#device-code-flow)
- [Ongoing Authentication](#ongoing-authentication)
  - [Manually Interacting with the Refresh Token](#manually-interacting-with-the-refresh-token)
  - [Creating a Liminal Client from a Stored Refresh Token](#creating-a-liminal-client-from-a-stored-refresh-token)
- [Endpoints](#endpoints)
  - [Getting Model Instances](#getting-model-instances)
  - [Managing Threads](#managing-threads)
  - [Submitting Prompts](#submitting-prompts)
- [Connection Pooling](#connection-pooling)
- [Running Examples](#running-examples)
- [Contributing](#contributing)

# Installation

```sh
pip install liminal-sdk-python
```

# Python Versions

`liminal` is currently supported on:

- Python 3.11
- Python 3.12

# Quickstart

Presuming the use of Microsoft Entra ID as your auth provider, instantiating a Liminal
API object is easy:

```python
import asyncio

from liminal import Client
from liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider


async def main() -> None:
    """Create the aiohttp session and run the example."""
    # Create an auth provider to authenticate the user:
    auth_provider = DeviceCodeFlowProvider("<TENANT_ID>", "<CLIENT_ID>")

    # Create the liminal SDK instance:
    liminal = Client(auth_provider, "<LIMINAL_API_SERVER_URL>")


asyncio.run(main())
```

You can see several examples of how to use this API object via the [`examples`][examples]
folder in this repo.

# Initial Authentication

Liminal supports the concept of authenticating via various auth providers. Currently,
the following auth providers are supported:

- Microsoft Entra ID

## Microsoft Entra ID

### Device Code Flow

This authentication process with Microsoft Entra ID involves an
[OAuth 2.0 Device Authorization Grant][oauth-device-auth-grant]. This flow requires you
to start your app, retrieve a device code from the logs produced by this SDK, and
provide that code to Microsoft via a web browser. Once you complete the login process,
the SDK will be authenticated for use with your Liminal instance.

To authenticate with this flow, you will need an Entra ID client and tenant ID:

- Log into your [Azure portal][azure-portal].
- Navigate to `Microsoft Entra ID`.
- Click on `App registrations`.
- Either create a new app registration or select an existing one.
- In the `Overview` of the registration, look for the `Application (client) ID` and
  `Directory (tenant) ID` values.

With a client ID and tenant ID, you can create a Liminal client object and authenticate
it:

```python
import asyncio

from liminal import Client
from liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider


async def main() -> None:
    """Create the aiohttp session and run the example."""
    # Create an auth provider to authenticate the user:
    auth_provider = DeviceCodeFlowProvider("<TENANT_ID>", "<CLIENT_ID>")

    # Create the liminal SDK instance and authenticate it:
    liminal = Client(auth_provider, "<LIMINAL_API_SERVER_URL>")
    await liminal.authenticate_from_auth_provider()


asyncio.run(main())
```

In your application logs, you will see a message that looks like this:

```
INFO:liminal:To sign in, use a web browser to open the page
https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.
```

Leaving your application running, open a browser at that URL and input the code as
instructed. Once you successfully complete authentication via Entra ID, your Liminal
client object will automatically authenticate with your Liminal API server.

# Ongoing Authentication

After the initial authentication with your auth provider, the Liminal client object will
internally store access and refresh tokens to ensure the ongoing ability to communicate
with your Liminal API server. The client object will automatically handle using the
stored refresh token to request new access tokens as appropriate.

## Manually Interacting with the Refresh Token

The Liminal client object provides a `add_refresh_token_callback` method to manually
interact with refresh tokens as they are generated. This is useful in situations where
you want to retrieve that token and do something else with (store it in a database, for
example). Every time a new refresh token is generated by the client object, the
registered callbacks will be called.

Refresh token callbacks are methods that take a single `str` parameter (denoting the
refresh token). These callbacks are not expected to return any value. Lastly, when
calling `add_refresh_token_callback`, the returned method allows you to cancel the
callback at any time.

```python
import asyncio

from liminal import Client
from liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider


async def main() -> None:
    """Create the aiohttp session and run the example."""
    # Create an auth provider to authenticate the user:
    auth_provider = DeviceCodeFlowProvider("<TENANT_ID>", "<CLIENT_ID>")

    # Create the liminal SDK instance and authenticate it:
    liminal = Client(microsoft_auth_provider, "<LIMINAL_API_SERVER_URL>")
    await liminal.authenticate_from_auth_provider()

    def do_something_with_refresh_token(refresh_token: str) -> None:
        """Do something with the refresh token."""
        pass

    # Register the refresh token callback:
    remove_callback = liminal.add_refresh_token_callback(
        do_something_with_refresh_token
    )

    # Later, if you want to remove the callback:
    remove_callback()


asyncio.run(main())
```

## Creating a Liminal Client from a Stored Refresh Token

Assuming you have a stored refresh token (collected from the callback process shown
above), it is simple to create a new Limina client using that token:

```python
import asyncio

from liminal import Client


async def main() -> None:
    """Create the aiohttp session and run the example."""
    # Retrieve your stored refresh_token:
    refresh_token = "12345"

    # Create the client:
    liminal = await client.authenticate_from_refresh_token(refresh_token=refresh_token)


asyncio.run(main())
```

# Endpoints

## Getting Model Instances

Every LLM instance connected in the Liminal admin dashboard is referred to as a "model
instance." The SDK provides several methods to interact with model instances:

```python
import asyncio

from liminal import Client
from liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider


async def main() -> None:
    # Assuming you have an authenticated `liminal` object:

    # Get all available model instances:
    model_instances = await liminal.llm.get_available_model_instances()
    # >>> [ModelInstance(...), ModelInstance(...)]

    # Get a specific model instance (if it exists):
    model_instance = await liminal.llm.get_model_instance("My Model")
    # >>> ModelInstance(...)


asyncio.run(main())
```

## Managing Threads

Threads are conversations with an LLM instance:

```python
import asyncio

from liminal import Client
from liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider


async def main() -> None:
    # Assuming you have an authenticated `liminal` object:

    # Get all available threads:
    threads = await liminal.thread.get_available()
    # >>> [Thread(...), Thread(...)]

    # Get a specific thread by ID:
    thread = await liminal.thread.get_by_id(123)
    # >>> Thread(...)

    # Some operations require a model instance:
    model_instance = await liminal.llm.get_model_instance("My Model")

    # Create a new thread:
    thread = await liminal.thread.create(model_instance.id, "New Thread")
    # >>> Thread(...)


asyncio.run(main())
```

## Submitting Prompts

Submitting prompts is easy:

```python
import asyncio

from liminal import Client
from liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider


async def main() -> None:
    # Assuming you have an authenticated `liminal` object:

    # Prompt operations require a model instance:
    model_instance = await liminal.llm.get_model_instance(model_instance_name)

    # Prompt operations optionally take an existing thread:
    thread = await liminal.thread.get_by_id(123)
    # >>> Thread(...)

    # Analayze a prompt for sensitive info:
    findings = await liminal.prompt.analyze(
        model_instance.id, "Here is a sensitive prompt"
    )
    # >>> AnalyzeResponse(...)

    # Cleanse input text by applying the policies defined in the Liminal admin
    # dashboard. You can optionally provide existing analysis finidings; if not
    # provided, analyze is # called automatically):
    cleansed = await liminal.prompt.cleanse(
        model_instance.id,
        "Here is a sensitive prompt",
        findings=findings,
        thread_id=thread.id,
    )
    # >>> CleanseResponse(...)

    # Submit a prompt to an LLM, cleansing it in the process (once again, providing optional
    # findings):
    response = await liminal.prompt.submit(
        model_instance.id,
        "Here is a sensitive prompt",
        findings=findings,
        thread_id=thread.id,
    )
    # >>> SubmitResponse(...)

    # Rehydrate a response with sensitive data:
    hydrated = await liminal.prompt.hydrate(
        model_instance.id, "Here is a response to rehdyrate", thread_id=thread.id
    )
    # >>> HydrateResponse(...)


asyncio.run(main())
```

# Connection Pooling

By default, the library creates a new connection to the Liminal API server with each
coroutine. If you are calling a large number of coroutines (or merely want to squeeze
out every second of runtime savings possible), an [`httpx`][httpx] `AsyncClient` can be
used for connection pooling:

```python
import asyncio

from liminal import Client
from liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider


async def main() -> None:
    # Create an auth provider to authenticate the user:
    microsoft_auth_provider = MicrosoftAuthProvider("<TENANT_ID>", "<CLIENT_ID>")

    # Create the liminal SDK instance with a shared HTTPX AsyncClient:
    async with httpx.AsyncClient() as client:
        liminal = Client(
            microsoft_auth_provider, "<LIMINAL_API_SERVER_URL>", httpx_client=client
        )

        # Get to work!
        # ...


asyncio.run(main())
```

Check out the examples, the tests, and the source files themselves for method
signatures and more examples.

# Running Examples

You can see examples of how to use this SDK via the [`examples`][examples] folder in
this repo. Each example follows a similar "call" format by asking for inputs via
environment variables; for example:

```sh
LIMINAL_API_SERVER_URL=https://api.DOMAIN.liminal.ai \
CLIENT_ID=xxxxxxxxxxxxxxxx \
TENANT_ID=xxxxxxxxxxxxxxxx \
MODEL_INSTANCE_NAME=model-instance-name \
python3 examples/quickstart_with_microsoft.py
```

# Contributing

Thanks to all of [our contributors][contributors] so far!

1. [Check for open features/bugs][issues] or [initiate a discussion on one][new-issue].
2. [Fork the repository][fork].
3. (_optional, but highly recommended_) Create a virtual environment: `python3 -m venv .venv`
4. (_optional, but highly recommended_) Enter the virtual environment: `source ./.venv/bin/activate`
5. Install the dev environment: `./scripts/setup.sh`
6. Code your new feature or bug fix on a new branch.
7. Write tests that cover your new functionality.
8. Run tests and ensure 100% code coverage: `poetry run pytest --cov liminal tests`
9. Update `README.md` with any new documentation.
10. Submit a pull request!

[azure-portal]: https://portal.azure.com
[ci-badge]: https://img.shields.io/github/actions/workflow/status/liminal-ai-security/liminal-sdk-python/test.yml
[ci]: https://github.com/liminal-ai-security/liminal-sdk-python/actions
[contributors]: https://github.com/liminal-ai-security/liminal-sdk-python/graphs/contributors
[examples]: https://github.com/liminal-ai-security/liminal-sdk-python/tree/development/examples
[fork]: https://github.com/liminal-ai-security/liminal-sdk-python/fork
[httpx]: https://www.python-httpx.org/
[issues]: https://github.com/liminal-ai-security/liminal-sdk-python/issues
[license-badge]: https://img.shields.io/pypi/l/liminal-sdk-python.svg
[license]: https://github.com/liminal-ai-security/liminal-sdk-python/blob/main/LICENSE
[new-issue]: https://github.com/liminal-ai-security/liminal-sdk-python/issues/new
[notion]: https://getnotion.com
[oauth-device-auth-grant]: https://oauth.net/2/grant-types/device-code/
[pypi-badge]: https://img.shields.io/pypi/v/liminal-sdk-python.svg
[pypi]: https://pypi.python.org/pypi/liminal-sdk-python
[version-badge]: https://img.shields.io/pypi/pyversions/liminal-sdk-python.svg
[version]: https://pypi.python.org/pypi/liminal-sdk-python

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/liminal-ai-security/liminal-sdk-python",
    "name": "liminal-sdk-python",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0.0,>=3.11.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "Aaron Bach",
    "author_email": "ab@liminal.ai",
    "download_url": "https://files.pythonhosted.org/packages/57/ae/c67bda068aa26bb5a57c414a54ff659b2fe4b7f91e80d19463d6bfb7d2e8/liminal_sdk_python-2024.4.3.tar.gz",
    "platform": null,
    "description": "# Liminal Python SDK\n\n[![CI][ci-badge]][ci]\n[![PyPI][pypi-badge]][pypi]\n[![Version][version-badge]][version]\n[![License][license-badge]][license]\n\nThe Liminal SDK for Python provides a clean, straightforward, `asyncio`-based interface\nfor interacting with the Liminal API.\n\n- [Installation](#installation)\n- [Python Versions](#python-versions)\n- [Quickstart](#quickstart)\n- [Initial Authentication](#initial-authentication)\n  - [Microsoft Entra ID](#microsoft-entra-id)\n    - [Device Code Flow](#device-code-flow)\n- [Ongoing Authentication](#ongoing-authentication)\n  - [Manually Interacting with the Refresh Token](#manually-interacting-with-the-refresh-token)\n  - [Creating a Liminal Client from a Stored Refresh Token](#creating-a-liminal-client-from-a-stored-refresh-token)\n- [Endpoints](#endpoints)\n  - [Getting Model Instances](#getting-model-instances)\n  - [Managing Threads](#managing-threads)\n  - [Submitting Prompts](#submitting-prompts)\n- [Connection Pooling](#connection-pooling)\n- [Running Examples](#running-examples)\n- [Contributing](#contributing)\n\n# Installation\n\n```sh\npip install liminal-sdk-python\n```\n\n# Python Versions\n\n`liminal` is currently supported on:\n\n- Python 3.11\n- Python 3.12\n\n# Quickstart\n\nPresuming the use of Microsoft Entra ID as your auth provider, instantiating a Liminal\nAPI object is easy:\n\n```python\nimport asyncio\n\nfrom liminal import Client\nfrom liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider\n\n\nasync def main() -> None:\n    \"\"\"Create the aiohttp session and run the example.\"\"\"\n    # Create an auth provider to authenticate the user:\n    auth_provider = DeviceCodeFlowProvider(\"<TENANT_ID>\", \"<CLIENT_ID>\")\n\n    # Create the liminal SDK instance:\n    liminal = Client(auth_provider, \"<LIMINAL_API_SERVER_URL>\")\n\n\nasyncio.run(main())\n```\n\nYou can see several examples of how to use this API object via the [`examples`][examples]\nfolder in this repo.\n\n# Initial Authentication\n\nLiminal supports the concept of authenticating via various auth providers. Currently,\nthe following auth providers are supported:\n\n- Microsoft Entra ID\n\n## Microsoft Entra ID\n\n### Device Code Flow\n\nThis authentication process with Microsoft Entra ID involves an\n[OAuth 2.0 Device Authorization Grant][oauth-device-auth-grant]. This flow requires you\nto start your app, retrieve a device code from the logs produced by this SDK, and\nprovide that code to Microsoft via a web browser. Once you complete the login process,\nthe SDK will be authenticated for use with your Liminal instance.\n\nTo authenticate with this flow, you will need an Entra ID client and tenant ID:\n\n- Log into your [Azure portal][azure-portal].\n- Navigate to `Microsoft Entra ID`.\n- Click on `App registrations`.\n- Either create a new app registration or select an existing one.\n- In the `Overview` of the registration, look for the `Application (client) ID` and\n  `Directory (tenant) ID` values.\n\nWith a client ID and tenant ID, you can create a Liminal client object and authenticate\nit:\n\n```python\nimport asyncio\n\nfrom liminal import Client\nfrom liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider\n\n\nasync def main() -> None:\n    \"\"\"Create the aiohttp session and run the example.\"\"\"\n    # Create an auth provider to authenticate the user:\n    auth_provider = DeviceCodeFlowProvider(\"<TENANT_ID>\", \"<CLIENT_ID>\")\n\n    # Create the liminal SDK instance and authenticate it:\n    liminal = Client(auth_provider, \"<LIMINAL_API_SERVER_URL>\")\n    await liminal.authenticate_from_auth_provider()\n\n\nasyncio.run(main())\n```\n\nIn your application logs, you will see a message that looks like this:\n\n```\nINFO:liminal:To sign in, use a web browser to open the page\nhttps://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.\n```\n\nLeaving your application running, open a browser at that URL and input the code as\ninstructed. Once you successfully complete authentication via Entra ID, your Liminal\nclient object will automatically authenticate with your Liminal API server.\n\n# Ongoing Authentication\n\nAfter the initial authentication with your auth provider, the Liminal client object will\ninternally store access and refresh tokens to ensure the ongoing ability to communicate\nwith your Liminal API server. The client object will automatically handle using the\nstored refresh token to request new access tokens as appropriate.\n\n## Manually Interacting with the Refresh Token\n\nThe Liminal client object provides a `add_refresh_token_callback` method to manually\ninteract with refresh tokens as they are generated. This is useful in situations where\nyou want to retrieve that token and do something else with (store it in a database, for\nexample). Every time a new refresh token is generated by the client object, the\nregistered callbacks will be called.\n\nRefresh token callbacks are methods that take a single `str` parameter (denoting the\nrefresh token). These callbacks are not expected to return any value. Lastly, when\ncalling `add_refresh_token_callback`, the returned method allows you to cancel the\ncallback at any time.\n\n```python\nimport asyncio\n\nfrom liminal import Client\nfrom liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider\n\n\nasync def main() -> None:\n    \"\"\"Create the aiohttp session and run the example.\"\"\"\n    # Create an auth provider to authenticate the user:\n    auth_provider = DeviceCodeFlowProvider(\"<TENANT_ID>\", \"<CLIENT_ID>\")\n\n    # Create the liminal SDK instance and authenticate it:\n    liminal = Client(microsoft_auth_provider, \"<LIMINAL_API_SERVER_URL>\")\n    await liminal.authenticate_from_auth_provider()\n\n    def do_something_with_refresh_token(refresh_token: str) -> None:\n        \"\"\"Do something with the refresh token.\"\"\"\n        pass\n\n    # Register the refresh token callback:\n    remove_callback = liminal.add_refresh_token_callback(\n        do_something_with_refresh_token\n    )\n\n    # Later, if you want to remove the callback:\n    remove_callback()\n\n\nasyncio.run(main())\n```\n\n## Creating a Liminal Client from a Stored Refresh Token\n\nAssuming you have a stored refresh token (collected from the callback process shown\nabove), it is simple to create a new Limina client using that token:\n\n```python\nimport asyncio\n\nfrom liminal import Client\n\n\nasync def main() -> None:\n    \"\"\"Create the aiohttp session and run the example.\"\"\"\n    # Retrieve your stored refresh_token:\n    refresh_token = \"12345\"\n\n    # Create the client:\n    liminal = await client.authenticate_from_refresh_token(refresh_token=refresh_token)\n\n\nasyncio.run(main())\n```\n\n# Endpoints\n\n## Getting Model Instances\n\nEvery LLM instance connected in the Liminal admin dashboard is referred to as a \"model\ninstance.\" The SDK provides several methods to interact with model instances:\n\n```python\nimport asyncio\n\nfrom liminal import Client\nfrom liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider\n\n\nasync def main() -> None:\n    # Assuming you have an authenticated `liminal` object:\n\n    # Get all available model instances:\n    model_instances = await liminal.llm.get_available_model_instances()\n    # >>> [ModelInstance(...), ModelInstance(...)]\n\n    # Get a specific model instance (if it exists):\n    model_instance = await liminal.llm.get_model_instance(\"My Model\")\n    # >>> ModelInstance(...)\n\n\nasyncio.run(main())\n```\n\n## Managing Threads\n\nThreads are conversations with an LLM instance:\n\n```python\nimport asyncio\n\nfrom liminal import Client\nfrom liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider\n\n\nasync def main() -> None:\n    # Assuming you have an authenticated `liminal` object:\n\n    # Get all available threads:\n    threads = await liminal.thread.get_available()\n    # >>> [Thread(...), Thread(...)]\n\n    # Get a specific thread by ID:\n    thread = await liminal.thread.get_by_id(123)\n    # >>> Thread(...)\n\n    # Some operations require a model instance:\n    model_instance = await liminal.llm.get_model_instance(\"My Model\")\n\n    # Create a new thread:\n    thread = await liminal.thread.create(model_instance.id, \"New Thread\")\n    # >>> Thread(...)\n\n\nasyncio.run(main())\n```\n\n## Submitting Prompts\n\nSubmitting prompts is easy:\n\n```python\nimport asyncio\n\nfrom liminal import Client\nfrom liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider\n\n\nasync def main() -> None:\n    # Assuming you have an authenticated `liminal` object:\n\n    # Prompt operations require a model instance:\n    model_instance = await liminal.llm.get_model_instance(model_instance_name)\n\n    # Prompt operations optionally take an existing thread:\n    thread = await liminal.thread.get_by_id(123)\n    # >>> Thread(...)\n\n    # Analayze a prompt for sensitive info:\n    findings = await liminal.prompt.analyze(\n        model_instance.id, \"Here is a sensitive prompt\"\n    )\n    # >>> AnalyzeResponse(...)\n\n    # Cleanse input text by applying the policies defined in the Liminal admin\n    # dashboard. You can optionally provide existing analysis finidings; if not\n    # provided, analyze is # called automatically):\n    cleansed = await liminal.prompt.cleanse(\n        model_instance.id,\n        \"Here is a sensitive prompt\",\n        findings=findings,\n        thread_id=thread.id,\n    )\n    # >>> CleanseResponse(...)\n\n    # Submit a prompt to an LLM, cleansing it in the process (once again, providing optional\n    # findings):\n    response = await liminal.prompt.submit(\n        model_instance.id,\n        \"Here is a sensitive prompt\",\n        findings=findings,\n        thread_id=thread.id,\n    )\n    # >>> SubmitResponse(...)\n\n    # Rehydrate a response with sensitive data:\n    hydrated = await liminal.prompt.hydrate(\n        model_instance.id, \"Here is a response to rehdyrate\", thread_id=thread.id\n    )\n    # >>> HydrateResponse(...)\n\n\nasyncio.run(main())\n```\n\n# Connection Pooling\n\nBy default, the library creates a new connection to the Liminal API server with each\ncoroutine. If you are calling a large number of coroutines (or merely want to squeeze\nout every second of runtime savings possible), an [`httpx`][httpx] `AsyncClient` can be\nused for connection pooling:\n\n```python\nimport asyncio\n\nfrom liminal import Client\nfrom liminal.auth.microsoft.device_code_flow import DeviceCodeFlowProvider\n\n\nasync def main() -> None:\n    # Create an auth provider to authenticate the user:\n    microsoft_auth_provider = MicrosoftAuthProvider(\"<TENANT_ID>\", \"<CLIENT_ID>\")\n\n    # Create the liminal SDK instance with a shared HTTPX AsyncClient:\n    async with httpx.AsyncClient() as client:\n        liminal = Client(\n            microsoft_auth_provider, \"<LIMINAL_API_SERVER_URL>\", httpx_client=client\n        )\n\n        # Get to work!\n        # ...\n\n\nasyncio.run(main())\n```\n\nCheck out the examples, the tests, and the source files themselves for method\nsignatures and more examples.\n\n# Running Examples\n\nYou can see examples of how to use this SDK via the [`examples`][examples] folder in\nthis repo. Each example follows a similar \"call\" format by asking for inputs via\nenvironment variables; for example:\n\n```sh\nLIMINAL_API_SERVER_URL=https://api.DOMAIN.liminal.ai \\\nCLIENT_ID=xxxxxxxxxxxxxxxx \\\nTENANT_ID=xxxxxxxxxxxxxxxx \\\nMODEL_INSTANCE_NAME=model-instance-name \\\npython3 examples/quickstart_with_microsoft.py\n```\n\n# Contributing\n\nThanks to all of [our contributors][contributors] so far!\n\n1. [Check for open features/bugs][issues] or [initiate a discussion on one][new-issue].\n2. [Fork the repository][fork].\n3. (_optional, but highly recommended_) Create a virtual environment: `python3 -m venv .venv`\n4. (_optional, but highly recommended_) Enter the virtual environment: `source ./.venv/bin/activate`\n5. Install the dev environment: `./scripts/setup.sh`\n6. Code your new feature or bug fix on a new branch.\n7. Write tests that cover your new functionality.\n8. Run tests and ensure 100% code coverage: `poetry run pytest --cov liminal tests`\n9. Update `README.md` with any new documentation.\n10. Submit a pull request!\n\n[azure-portal]: https://portal.azure.com\n[ci-badge]: https://img.shields.io/github/actions/workflow/status/liminal-ai-security/liminal-sdk-python/test.yml\n[ci]: https://github.com/liminal-ai-security/liminal-sdk-python/actions\n[contributors]: https://github.com/liminal-ai-security/liminal-sdk-python/graphs/contributors\n[examples]: https://github.com/liminal-ai-security/liminal-sdk-python/tree/development/examples\n[fork]: https://github.com/liminal-ai-security/liminal-sdk-python/fork\n[httpx]: https://www.python-httpx.org/\n[issues]: https://github.com/liminal-ai-security/liminal-sdk-python/issues\n[license-badge]: https://img.shields.io/pypi/l/liminal-sdk-python.svg\n[license]: https://github.com/liminal-ai-security/liminal-sdk-python/blob/main/LICENSE\n[new-issue]: https://github.com/liminal-ai-security/liminal-sdk-python/issues/new\n[notion]: https://getnotion.com\n[oauth-device-auth-grant]: https://oauth.net/2/grant-types/device-code/\n[pypi-badge]: https://img.shields.io/pypi/v/liminal-sdk-python.svg\n[pypi]: https://pypi.python.org/pypi/liminal-sdk-python\n[version-badge]: https://img.shields.io/pypi/pyversions/liminal-sdk-python.svg\n[version]: https://pypi.python.org/pypi/liminal-sdk-python\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "The Liminal SDK for Python",
    "version": "2024.4.3",
    "project_urls": {
        "Bug Tracker": "https://github.com/liminal-ai-security/liminal-sdk-python/issues",
        "Changelog": "https://github.com/liminal-ai-security/liminal-sdk-python/releases",
        "Homepage": "https://github.com/liminal-ai-security/liminal-sdk-python",
        "Repository": "https://github.com/liminal-ai-security/liminal-sdk-python"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a1d7e04b0802e7c4401dfca9f5f227baae5b262f1bdb5ddd1c8245cc31ad2fcf",
                "md5": "52f03dc3c1b4aad162d7ce578c4cab1c",
                "sha256": "e2a2bef594dce7d17fee13856743cd6d0e8d238b9dd785cc49b69a8ccd9b15d4"
            },
            "downloads": -1,
            "filename": "liminal_sdk_python-2024.4.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "52f03dc3c1b4aad162d7ce578c4cab1c",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0.0,>=3.11.8",
            "size": 21468,
            "upload_time": "2024-04-12T05:10:35",
            "upload_time_iso_8601": "2024-04-12T05:10:35.461831Z",
            "url": "https://files.pythonhosted.org/packages/a1/d7/e04b0802e7c4401dfca9f5f227baae5b262f1bdb5ddd1c8245cc31ad2fcf/liminal_sdk_python-2024.4.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "57aec67bda068aa26bb5a57c414a54ff659b2fe4b7f91e80d19463d6bfb7d2e8",
                "md5": "2d1da9baec0739ac1f6702a2b0d7e7a4",
                "sha256": "663d76a4b512d9c1eff234a88b687ac2c79b8cd1ef4faa4ee2536b14a916d704"
            },
            "downloads": -1,
            "filename": "liminal_sdk_python-2024.4.3.tar.gz",
            "has_sig": false,
            "md5_digest": "2d1da9baec0739ac1f6702a2b0d7e7a4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0.0,>=3.11.8",
            "size": 21898,
            "upload_time": "2024-04-12T05:10:36",
            "upload_time_iso_8601": "2024-04-12T05:10:36.512440Z",
            "url": "https://files.pythonhosted.org/packages/57/ae/c67bda068aa26bb5a57c414a54ff659b2fe4b7f91e80d19463d6bfb7d2e8/liminal_sdk_python-2024.4.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-12 05:10:36",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "liminal-ai-security",
    "github_project": "liminal-sdk-python",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "liminal-sdk-python"
}
        
Elapsed time: 0.30434s