Metadata-Version: 2.4
Name: posf
Version: 0.1.1
Summary: A Polars adapter for your Salesforce data
License-Expression: MIT
Project-URL: Homepage, https://github.com/stephenlf/posf
Project-URL: Repository, https://github.com/stephenlf/posf.git
Keywords: salesforce,notebook,jupyter,marimo,polars
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Programming Language :: SQL
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Information Technology
Classifier: Framework :: IPython
Classifier: Framework :: Jupyter
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Database
Classifier: Topic :: Database :: Front-Ends
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: polars>=1.39.3
Requires-Dist: simple-salesforce>=1.12.9
Provides-Extra: marimo
Requires-Dist: marimo>=0.17.0; extra == "marimo"
Dynamic: license-file

# posf

_(poh ⋅ sef)_ A Salesforce client in Python for data engineers. Read from and write to Salesforce with Polars dataframes.

## Usage

```python
import posf
import polars as pl

# Connect to Salesforce
pf = posf.Posf.from_cli("prod")

# Describe table

pf.describe("Opportunity")

# Query
df: pl.DataFrame = pf.query("""
    SELECT Id, Name
    FROM Opportunity
""")

# Manipulate data in Polars dataframes
df = df.select(
    [
        pl.col("Id"),
        pl.col("Name").str.to_titlecase()
    ]
)

# Write back to Salesforce
pf.update('Account', df)
```

## Getting Started

First, add `posf` to your project.

```bash
uv add posf
```

Then, choose from any number of connection options.
```python
from posf import Posf
import simple_salesforce

pf = Posf.from_cli() # Reuse `sf` CLI connection for local dev
pf = Posf.from_security_token() # Use security token for quick start
pf = Posf(simple_salesforce.Salesforce(...)) # Pass in a simple-salesforce
                                             # client directly
```

## Transactions

Use the `composite_request` API to work with ACID transactions.

```python
tx = pf.composite_request()
tx.insert(df1)
tx.update(df2)
tx.delete(df3)
insert_res, update_res, delete_res = tx.commit()
```

## Working with Notebooks

posf is specially designed with [Marimo](https://marimo.io/) in mind. All of the non-idempotent actions may be gated behind a Marimo run button. This prevents executing the same action multiple times as cells are autorun. To do this, pass the run button's `value` property to the `run` parameter in any method that executes DML. These include `insert`, `update`, `upsert`, `delete`, and `commit`.

```python
# Cell 1
import marimo as mo
import posf

# Cell 2
pf = posf.from_cli('prod')
run_button = mo.ui.run_button(label="Commit")

# Cell 3
# insert will not execute until run button is clicked
pf.insert(my_data, 'Account', run=run_button.value)
```

There are a number of [examples](./examples/marimo-snippets/) available to illustrate this package. These can be loaded as [Marimo snippets](https://docs.marimo.io/guides/configuration/snippets/) by saving the contents of [examples/marimo-snippets](./examples/marimo-snippets/) to your snippets directory (`snippets.custom_paths` in `marimo config show`).
