Metadata-Version: 2.1
Name: inngest
Version: 0.1.2
Summary: Python SDK for Inngest
Project-URL: Homepage, https://github.com/inngest/inngest-py
Project-URL: Bug Tracker, https://github.com/inngest/inngest-py/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Flask
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: httpx >=0.24.0
Requires-Dist: pydantic >=2.1.1
Provides-Extra: extra
Requires-Dist: Flask ==3.0.0 ; extra == 'extra'
Requires-Dist: black ==23.10.0 ; extra == 'extra'
Requires-Dist: build ==1.0.3 ; extra == 'extra'
Requires-Dist: fastapi ==0.104.0 ; extra == 'extra'
Requires-Dist: isort ==5.12.0 ; extra == 'extra'
Requires-Dist: mypy ==1.6.1 ; extra == 'extra'
Requires-Dist: pylint ==3.0.1 ; extra == 'extra'
Requires-Dist: pytest ==7.4.2 ; extra == 'extra'
Requires-Dist: pytest-xdist[psutil] ==3.3.1 ; extra == 'extra'
Requires-Dist: python-json-logger ==2.0.7 ; extra == 'extra'
Requires-Dist: toml ==0.10.2 ; extra == 'extra'
Requires-Dist: tornado ==6.3.3 ; extra == 'extra'
Requires-Dist: types-toml ==0.10.8.7 ; extra == 'extra'
Requires-Dist: types-tornado ==5.1.1 ; extra == 'extra'
Requires-Dist: uvicorn ==0.23.2 ; extra == 'extra'

<div align="center">
  <br/>
    <a href="https://www.inngest.com"><img src="https://user-images.githubusercontent.com/306177/191580717-1f563f4c-31e3-4aa0-848c-5ddc97808a9a.png" width="250" /></a>
  <br/>
  <br/>
  <p>
    Serverless event-driven queues, background jobs, and scheduled jobs for Python.<br />
    Works with any framework and platform.
  </p>
  Read the <a href="https://www.inngest.com/docs?ref=github-inngest-js-readme">documentation</a> and get started in minutes.
  <br/>
  <p>

[![pypi](https://img.shields.io/pypi/v/inngest.svg)](https://pypi.python.org/pypi/inngest)
![versions](https://img.shields.io/pypi/pyversions/inngest.svg)
[![discord](https://img.shields.io/discord/842170679536517141?label=discord)](https://www.inngest.com/discord)
[![twitter](https://img.shields.io/twitter/follow/inngest?style=social)](https://twitter.com/inngest)

  </p>
</div>

<hr />

# Inngest Python SDK

> 🚧 Currently in beta! It hasn't been battle-tested in production environments yet.

Supported frameworks:

- Fast API
- Flask
- Tornado

## Usage

> 💡 Most of these examples don't show `async` functions but you can mix `async` and non-`async` functions in the same app!

- [Basic](#basic-no-steps)
- [Step run](#step-run)
- [Async function](#async-function)

### Basic (no steps)

This is a minimal example of an Inngest function. It's missing some of our features but it's a good starting point.

```py
import flask
import inngest.flask
import requests

@inngest.create_function(
    fn_id="find_person",
    trigger=inngest.TriggerEvent(event="app/person.find"),
)
async def fetch_person(
    *,
    event: inngest.Event,
    step: inngest.Step,
    **_kwargs: object,
) -> dict:
    person_id = event.data["person_id"]
    res = requests.get(f"https://swapi.dev/api/people/{person_id}")
    return res.json()

app = flask.Flask(__name__)
inngest_client = inngest.Inngest(app_id="flask_example")

# Register functions with the Inngest server
inngest.flask.serve(
    app,
    inngest_client,
    [fetch_person],
)

app.run(port=8000)
```

### Step run

The following example registers a function that will:

1. Get the person ID from the event
1. Fetch the person with that ID
1. Fetch the person's ships
1. Return a summary dict

```py
@inngest.create_function(
    fn_id="find_ships",
    trigger=inngest.TriggerEvent(event="app/ships.find"),
)
def fetch_ships(
    *,
    event: inngest.Event,
    step: inngest.StepSync,
    **_kwargs: object,
) -> dict:
    """
    Find all the ships a person has.
    """

    person_id = event.data["person_id"]

    def _fetch_person() -> dict:
        res = requests.get(f"https://swapi.dev/api/people/{person_id}")
        return res.json()

    # Wrap the function with step.run to enable retries
    person = step.run("fetch_person", _fetch_person)

    def _fetch_ship(url: str) -> dict:
        res = requests.get(url)
        return res.json()

    ship_names = []
    for ship_url in person["starships"]:
        # step.run works in loops!
        ship = step.run("fetch_ship", lambda: _fetch_ship(ship_url))

        ship_names.append(ship["name"])

    return {
        "person_name": person["name"],
        "ship_names": ship_names,
    }
```

### Async functions

```py
@inngest.create_function(
    fn_id="find_person",
    trigger=inngest.TriggerEvent(event="app/person.find"),
)
async def fetch_person(
    *,
    event: inngest.Event,
    step: inngest.Step,
    **_kwargs: object,
) -> dict:
    person_id = event.data["person_id"]
    async with httpx.AsyncClient() as client:
        res = await client.get(f"https://swapi.dev/api/people/{person_id}")
        return res.json()
```

> 💡 You can mix `async` and non-`async` functions in the same app!
