Skip to content

Commit

Permalink
deploy: 77b8832
Browse files Browse the repository at this point in the history
  • Loading branch information
elijahbenizzy committed Feb 11, 2025
1 parent 3a50abc commit da3c337
Show file tree
Hide file tree
Showing 15 changed files with 1,014 additions and 119 deletions.
Binary file modified pull/505/.doctrees/concepts/actions.doctree
Binary file not shown.
Binary file modified pull/505/.doctrees/concepts/state-persistence.doctree
Binary file not shown.
Binary file modified pull/505/.doctrees/environment.pickle
Binary file not shown.
Binary file modified pull/505/.doctrees/reference/application.doctree
Binary file not shown.
Binary file modified pull/505/.doctrees/reference/persister.doctree
Binary file not shown.
8 changes: 6 additions & 2 deletions pull/505/_sources/concepts/actions.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ Will require the inputs to be passed in at runtime. See below for how to do that
This means that the application does not *need* the inputs to be set.

Note: to access ``app_id`` and ``partition_key`` in your running application, you can have the :py:class:`ApplicationContext <burr.core.application.ApplicationContext>`
Note: to access application-level metadata such as ``app_id``, ``partition_key``, ``sequence_id``, and ``action_name`` in your running application, you can have the :py:class:`ApplicationContext <burr.core.application.ApplicationContext>`
injected into your Burr Actions. This is done by adding ``__context`` to the action signature:

.. code-block:: python
Expand All @@ -121,6 +121,8 @@ injected into your Burr Actions. This is done by adding ``__context`` to the act
def my_action(state: State, __context: ApplicationContext) -> State:
app_id = __context.app_id
partition_key = __context.partition_key
action_name = __context.action_name
sequence_id = __context.sequence_id
...
Expand Down Expand Up @@ -303,7 +305,9 @@ that have similar capabilities as one, using a variety of :ref:`application <app
return state.update(**result)
This can be referred to either as the name of the action within the application, and/or as the tag
``response_to_display``.
``response_to_display`` -- referred to as ``@tag:response_to_display`` in the ``halt_after`` or ``halt_before`` parameters
of :py:func:`Application.run <burr.core.application.Application.run>`, :py:func:`Application.iterate <burr.core.application.Application.iterate>`, etc.
APIs.

In all function-based APIs, you can pass in a list of tags with the ``tags`` parameter.
In class-based APIs, you can set the ``tags`` property.
73 changes: 70 additions & 3 deletions pull/505/_sources/concepts/state-persistence.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Note that ``partition_key`` can be `None` if this is not relevant. A UUID is alw

You set these values using the :py:meth:`with_identifiers() <burr.core.application.ApplicationBuilder.with_identifiers>` method.

Note: to access ``app_id`` and ``partition_key`` in your running application, you can have the :py:class:`ApplicationContext <burr.core.application.ApplicationContext>`
Note: to access application-level metadata such as ``app_id``, ``partition_key``, ``sequence_id``, and ``action_name`` in your running application, you can have the :py:class:`ApplicationContext <burr.core.application.ApplicationContext>`
injected into your Burr Actions. This is done by adding ``__context`` to the action signature:

.. code-block:: python
Expand All @@ -54,6 +54,8 @@ injected into your Burr Actions. This is done by adding ``__context`` to the act
def my_action(state: State, __context: ApplicationContext) -> State:
app_id = __context.app_id
partition_key = __context.partition_key
action_name = __context.action_name
sequence_id = __context.sequence_id
...
Expand Down Expand Up @@ -115,7 +117,7 @@ To make the above more concrete, let's look at a basic chatbot:

.. code-block:: python
state_persister = SQLLitePersister(db_path=".sqllite.db", table_name="burr_state")
state_persister = SQLLitePersister.from_values(db_path=".sqllite.db", table_name="burr_state")
app = (
ApplicationBuilder()
.with_actions(
Expand Down Expand Up @@ -151,10 +153,75 @@ See :ref:`available persisters here <persistersref>`.
Note that the tracker also allows reloading from a file, but this is not recommended for production use.


Persister Usage
______________________________
We follow the naming convention ``b_database-dependency-library``, where the ``b_`` is used to avoid name
clashing with the underlying library. We chose the library name in case we implement the same database
persister with different dependency libraries to keep the class naming convention.

To initialize the persister we recommend using one of the two class methods: ``.from_config(...)`` or ``.from_values(...)`` that
establish a connection to the database and return the persister object. In case you already have a database connection
established (or using a connection pool), you can also initialize the persister directly and pass in the database
connection as the first argument.

We recommend that you manually handle the database connection cleanup. For now, in the case of
synchronous persisters, the connection gets closed when the object is deleted. For asynchronous
persisters this is not possible. Therefore, we suggest that you either use the persister as a context
manager

.. code-block:: python
with SQLLitePersister.from_values(
db_path=".sqllite.db",
table_name="burr_state"
) as state_persister:
app = (
ApplicationBuilder()
.with_actions(...)
.with_transitions(...)
.initialize_from(
state_persister, ...
)
.with_state_persister(state_persister)
.with_identifiers(app_id=app_id)
.build()
)
*_, state = app.run(...)
or manually close the connection to the database, by using the `.cleanup()` method of the persister

.. code-block:: python
state_persister = SQLLitePersister.from_values(db_path=".sqllite.db", table_name="burr_state")
app = (
ApplicationBuilder()
.with_actions(...)
.with_transitions(...)
.initialize_from(
state_persister, ...
)
.with_state_persister(state_persister)
.with_identifiers(app_id=app_id)
.build()
)
try:
*_, state = app.run(...)
except Exception as e:
...
finally:
state_persister.cleanup()
to ensure no database connection leakage.


Customizing State Persistence
-----------------------------

Burr exposes the :py:class:`BaseStatePersister <burr.core.persistence.BaseStatePersister>` API for custom state persistence. Implement,
Burr exposes two APIs :py:class:`BaseStatePersister <burr.core.persistence.BaseStatePersister>` (sync) and
:py:class:`AsyncBaseStatePersister <burr.core.persistence.AsyncBaseStatePersister>` (async) for custom state persistence. Implement,
pass into the above functions, and you can write to whatever database you want! Please contribute back to the community if you do so.


Expand Down
56 changes: 50 additions & 6 deletions pull/505/_sources/reference/persister.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,34 @@
State Persistence
=================

.. _persistersref:

Burr provides a set of tools to make loading and saving state easy. These are functions
that will be used by lifecycle hooks to save and load state.

We currently support the following database integrations:

.. table:: Burr Implemented Persisters
:widths: auto

+-------------+-----------------------------------------------------------------+---------------------------------------------------------------------+
| Database | Sync | Async |
+=============+===========+=====================================================+===============+=====================================================+
| SQLite | sqlite3 | :ref:`SQLitePersister <syncsqliteref>` | aiosqlite | :ref:`AsyncSQLitePersister <asyncsqliteref>` |
+-------------+-----------+-----------------------------------------------------+---------------+-----------------------------------------------------+
| PostgreSQL | psycopg2 | :ref:`PostgreSQLPersister <syncpostgresref>` | asyncpg | :ref:`AsyncPostgreSQLPersister <asyncpostgresref>` |
+-------------+-----------+-----------------------------------------------------+---------------+-----------------------------------------------------+
| Redis | redis | :ref:`RedisBasePersister <syncredisref>` | redis.asyncio | :ref:`AsyncRedisBasePersister <asyncredisref>` |
+-------------+-----------+-----------------------------------------------------+---------------+-----------------------------------------------------+
| MongoDB | pymongo | :ref:`MongoDBBasePersister <syncmongoref>` |||
+-------------+-----------+-----------------------------------------------------+---------------+-----------------------------------------------------+

We follow the naming convention ``b_dependency-library``, where the ``b_`` is used to avoid name
clashing with the underlying library. We chose the library name in case we implement the same database
persister with different dependency libraries to keep the class naming convention.

If you want to implement your own state persister (to bridge it with a database), you should implement
the ``BaseStatePersister`` interface.
the ``BaseStatePersister`` or the ``AsyncBaseStatePersister`` interface.

.. autoclass:: burr.core.persistence.BaseStatePersister
:members:
Expand Down Expand Up @@ -57,27 +80,32 @@ Internally, this interface combines the following two interfaces:
Supported Sync Implementations
================================

.. _persistersref:

Currently we support the following, although we highly recommend you contribute your own! We will be adding more shortly.

.. _syncsqliteref:

.. autoclass:: burr.core.persistence.SQLitePersister
:members:

.. automethod:: __init__

.. _syncpostgresref:

.. autoclass:: burr.integrations.persisters.postgresql.PostgreSQLPersister
.. autoclass:: burr.integrations.persisters.b_psycopg2.PostgreSQLPersister
:members:

.. automethod:: __init__

.. _syncredisref:

.. autoclass:: burr.integrations.persisters.b_redis.RedisBasePersister
:members:

.. automethod:: __init__

.. autoclass:: burr.integrations.persisters.b_mongodb.MongoDBBasePersister
.. _syncmongoref:

.. autoclass:: burr.integrations.persisters.b_pymongo.MongoDBBasePersister
:members:

.. automethod:: __init__
Expand All @@ -90,11 +118,27 @@ although it uses different mechanisms to save state (as it tracks more than just
Supported Async Implementations
================================

.. _asyncpersistersref:

Currently we support the following, although we highly recommend you contribute your own! We will be adding more shortly.

.. _asyncpersistersref:
.. _asyncsqliteref:

.. autoclass:: burr.integrations.persisters.b_aiosqlite.AsyncSQLitePersister
:members:

.. automethod:: __init__

.. _asyncpostgresref:

.. autoclass:: burr.integrations.persisters.b_asyncpg.AsyncPostgreSQLPersister
:members:

.. automethod:: __init__

.. _asyncredisref:

.. autoclass:: burr.integrations.persisters.b_redis.AsyncRedisBasePersister
:members:

.. automethod:: __init__
8 changes: 6 additions & 2 deletions pull/505/concepts/actions/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -457,14 +457,16 @@ <h1>Actions<a class="headerlink" href="#actions" title="Link to this heading">¶
</pre></div>
</div>
<p>This means that the application does not <em>need</em> the inputs to be set.</p>
<p>Note: to access <code class="docutils literal notranslate"><span class="pre">app_id</span></code> and <code class="docutils literal notranslate"><span class="pre">partition_key</span></code> in your running application, you can have the <a class="reference internal" href="../../reference/application/#burr.core.application.ApplicationContext" title="burr.core.application.ApplicationContext"><code class="xref py py-class docutils literal notranslate"><span class="pre">ApplicationContext</span></code></a>
<p>Note: to access application-level metadata such as <code class="docutils literal notranslate"><span class="pre">app_id</span></code>, <code class="docutils literal notranslate"><span class="pre">partition_key</span></code>, <code class="docutils literal notranslate"><span class="pre">sequence_id</span></code>, and <code class="docutils literal notranslate"><span class="pre">action_name</span></code> in your running application, you can have the <a class="reference internal" href="../../reference/application/#burr.core.application.ApplicationContext" title="burr.core.application.ApplicationContext"><code class="xref py py-class docutils literal notranslate"><span class="pre">ApplicationContext</span></code></a>
injected into your Burr Actions. This is done by adding <code class="docutils literal notranslate"><span class="pre">__context</span></code> to the action signature:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">burr.core</span><span class="w"> </span><span class="kn">import</span> <span class="n">action</span><span class="p">,</span> <span class="n">State</span><span class="p">,</span> <span class="n">ApplicationContext</span>

<span class="nd">@action</span><span class="p">(</span><span class="n">reads</span><span class="o">=</span><span class="p">[</span><span class="o">...</span><span class="p">],</span> <span class="n">writes</span><span class="o">=</span><span class="p">[</span><span class="o">...</span><span class="p">])</span>
<span class="k">def</span><span class="w"> </span><span class="nf">my_action</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">State</span><span class="p">,</span> <span class="n">__context</span><span class="p">:</span> <span class="n">ApplicationContext</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">State</span><span class="p">:</span>
<span class="n">app_id</span> <span class="o">=</span> <span class="n">__context</span><span class="o">.</span><span class="n">app_id</span>
<span class="n">partition_key</span> <span class="o">=</span> <span class="n">__context</span><span class="o">.</span><span class="n">partition_key</span>
<span class="n">action_name</span> <span class="o">=</span> <span class="n">__context</span><span class="o">.</span><span class="n">action_name</span>
<span class="n">sequence_id</span> <span class="o">=</span> <span class="n">__context</span><span class="o">.</span><span class="n">sequence_id</span>
<span class="o">...</span>
</pre></div>
</div>
Expand Down Expand Up @@ -615,7 +617,9 @@ <h2>Tagging Actions<a class="headerlink" href="#tagging-actions" title="Link to
</pre></div>
</div>
<p>This can be referred to either as the name of the action within the application, and/or as the tag
<code class="docutils literal notranslate"><span class="pre">response_to_display</span></code>.</p>
<code class="docutils literal notranslate"><span class="pre">response_to_display</span></code> – referred to as <code class="docutils literal notranslate"><span class="pre">&#64;tag:response_to_display</span></code> in the <code class="docutils literal notranslate"><span class="pre">halt_after</span></code> or <code class="docutils literal notranslate"><span class="pre">halt_before</span></code> parameters
of <a class="reference internal" href="../../reference/application/#burr.core.application.Application.run" title="burr.core.application.Application.run"><code class="xref py py-func docutils literal notranslate"><span class="pre">Application.run</span></code></a>, <a class="reference internal" href="../../reference/application/#burr.core.application.Application.iterate" title="burr.core.application.Application.iterate"><code class="xref py py-func docutils literal notranslate"><span class="pre">Application.iterate</span></code></a>, etc.
APIs.</p>
<p>In all function-based APIs, you can pass in a list of tags with the <code class="docutils literal notranslate"><span class="pre">tags</span></code> parameter.
In class-based APIs, you can set the <code class="docutils literal notranslate"><span class="pre">tags</span></code> property.</p>
</section>
Expand Down
Loading

0 comments on commit da3c337

Please sign in to comment.