Metadata-Version: 2.4
Name: fennflow
Version: 0.7.0
Summary: Atomic-like Agnostic Object Storage Framework, the Pydantic way
Project-URL: Source, https://github.com/Alex-FIR-IT/FennFlow
Project-URL: Documentation, https://github.com/Alex-FIR-IT/FennFlow/blob/master/docs/README.md
Project-URL: Changelog, https://github.com/Alex-FIR-IT/FennFlow/releases
Project-URL: Roadmap, https://github.com/users/Alex-FIR-IT/projects/2/views/2
Author-email: AlexFIR <osintfir@gmail.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: aiobotocore>=3.0.0
Requires-Dist: aiosqlite>=0.20.0
Requires-Dist: certifi>=2023.11.17
Requires-Dist: pydantic>=2.0.0
Requires-Dist: sqlalchemy[asyncio]>=2.0.0
Description-Content-Type: text/markdown

<div align="center">
    <a href="https://github.com/Alex-FIR-IT/FennFlow">
    <picture>
      <img src="https://c438939f-e2e4-4a9c-a938-fc6e872413f4.selstorage.ru/github.png" alt="FennFlow">
    </picture>
  </a>
</div>
<div align="center">
  <h3>Atomic-like Agnostic Object Storage Framework, the Pydantic way</h3>
</div>
<div align="center">
  <a href="https://github.com/Alex-FIR-IT/FennFlow/actions/workflows/coverage-report.yml"><img src="https://github.com/Alex-FIR-IT/FennFlow/actions/workflows/coverage-report.yml/badge.svg?branch=master" alt="CI"></a>
  <a href="https://app.codacy.com/gh/Alex-FIR-IT/FennFlow/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage"><img src="https://app.codacy.com/project/badge/Coverage/3db23fc6c6f248f2926731b0bdf0d012" alt="Codacy Coverage"></a>
  <a href="https://github.com/users/Alex-FIR-IT/projects/2/views/2"><img src="https://img.shields.io/badge/Roadmap-green?logo=github" alt="Roadmap"></a>
  <a href="https://pypi.python.org/pypi/fennflow"><img src="https://img.shields.io/pypi/v/fennflow" alt="PyPI"></a>  
  <a href="https://github.com/Alex-FIR-IT/FennFlow"><img src="https://img.shields.io/pypi/pyversions/fennflow?style=flat&logo=python&logoColor=white" alt="versions"></a>
  <a href="https://github.com/Alex-FIR-IT/fennflow/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-brightgreen" alt="License: MIT"></a>
  <a href="https://github.com/Alex-FIR-IT/fennflow/commits/master/"><img src="https://img.shields.io/github/last-commit/Alex-FIR-IT/fennflow?logo=github" alt="Last Commit"></a>
  <a href="https://app.codacy.com/gh/Alex-FIR-IT/FennFlow/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img src="https://app.codacy.com/project/badge/Grade/3db23fc6c6f248f2926731b0bdf0d012" alt="Codacy Grade"></a>
</div>

---

**Documentation**: [📖 Docs](https://alex-fir-it.github.io/FennFlow/)

---

### <em>FennFlow is a Python s3 framework designed to help you quickly, confidently, and painlessly manipulate files in your object storage implementing SSOT pattern and Saga compensation flow.</em>

## Why use FennFlow?

Working with aiobotocore often feels like handling raw bytes and dicts. `FennFlow` wraps S3 operations into a high-level
Unit of Work pattern, providing:

- **SSOT** — the backend is the single source of truth for your file storage. No matter what your file storage contains,
  the backend ensures a consistent view of what exists.
- **Saga compensation flow** — if something fails mid-operation, all previous actions are automatically compensated in
  reverse order, leaving storage in a consistent state.
- **Clean Architecture** — treat S3 as proper repositories using mixins (`PutRepository`, `GetRepository`, etc.).
- **Pydantic-powered models** — work with `TextContent`, `JsonContent`, `ImageContent` and others instead of raw bytes.
- **Testability** — swap S3ConnectorConfig for InMemoryConnectorConfig and point the backend at an in-memory SQLite
  database. Zero infrastructure, zero mocks.

## Supported Connectors

| Connector        | Description                                  | Documentation                                                                                 |
|------------------|----------------------------------------------|-----------------------------------------------------------------------------------------------|
| AWS S3 (default) | s3 compatible object storage via aiobotocore | [📖 Docs](https://alex-fir-it.github.io/FennFlow/core_concepts/connectors/#s3connector)       |
| In-Memory        | great for and tests and development          | [📖 Docs](https://alex-fir-it.github.io/FennFlow/core_concepts/connectors/#inmemoryconnector) |

## Supported Backends

FennFlow uses backend as a source of truth for your file storage.
No matter what your file storage contains, backend ensures your data is consistent.

| Backend              | Description                                             | Documentation                                                                               |
|----------------------|---------------------------------------------------------|---------------------------------------------------------------------------------------------|
| SQLAlchemy (default) | persistent metadata backend, great for all environments | [📖 Docs](https://alex-fir-it.github.io/FennFlow/core_concepts/backends/#sqlalchemybackend) |
| In-Memory            | great for and tests, development                        | [📖 Docs](https://alex-fir-it.github.io/FennFlow/core_concepts/backends/#inmemorybackend)   |

### Backend Comparison

|                    | Raw aiobotocore                                   | SQLAlchemy (default)                                         |
|--------------------|---------------------------------------------------|--------------------------------------------------------------|
| **Consistency**    | 🔴 None<br>No link between files and metadata     | ✅ High<br>Persistent across restarts                         |
| **Compensation**   | 🔴 None<br>Orphaned files on failure              | ✅ High<br>Automatic within session                           |
| **Reliability**    | 🔴 Low<br>Failures leave storage in unknown state | ✅ High<br>Consistent state guaranteed across restarts        |
| **Latency**        | ✅ Lowest<br>Pure S3 network overhead only         | 🟡 Low/middle<br>DB overhead                                 |
| **Infrastructure** | ✅ None                                            | ✅ None<br>SQLite by default                                  |
| **Memory usage**   | ✅ None                                            | ✅ Minimal<br>Metadata persisted to disk, not held in-process |

## Quick Start

Here's a minimal example of FennFlow:

```python3
import asyncio

from fennflow import ConfigDict, UnitOfWork
from fennflow.backends import SqlalchemyBackendConfig
from fennflow.connectors import S3ConnectorConfig
from fennflow.files import BinaryContent, JsonContent, MediaType, TextContent
from fennflow.repositories import (
    DeleteRepository,
    GetRepository,
    ListRepository,
    PutRepository,
    S3RepoField,
    )


# 1. Define your repository with mixins
class CrudRepository(
    PutRepository,
    DeleteRepository,
    GetRepository,
    ListRepository,
    ):
    pass


# 2. Set up your Unit of Work
class UOW(UnitOfWork):
    my_files = S3RepoField(CrudRepository, bucket_name="my_files")
    config = ConfigDict(
        backend=SqlalchemyBackendConfig(),
        connector=S3ConnectorConfig(),
        )


async def main():
    text_file = TextContent.from_content("Hello, world!")
    json_file = JsonContent.from_content([1, 2, 3])

    from_path_binary_file = BinaryContent.from_local_path("my_file.txt")
    binary_file = BinaryContent(data=b"some bytes", media_type=MediaType.TEXT_PLAIN)

    async with UOW() as uow:
        await uow.my_files.at("folder1").put(
            text_file,
            json_file,
            from_path_binary_file,
            binary_file,
            )

        paths = await uow.my_files.at("folder1").list()
        print(paths)  # ListResponse[Filepath, ...]

        files = await uow.my_files.get(*paths)
        print(files)  # MediaResponse[TextContent, JsonContent, TextContent, BaseBinary]


if __name__ == "__main__":
    asyncio.run(main())
```

(This example is complete, it can be run “as is”, assuming you’ve installed the fennflow package)

## Next Steps

To try FennFlow for yourself, [clone it](https://github.com/Alex-FIR-IT/FennFlow) and follow the instructions
in the [examples](https://alex-fir-it.github.io/FennFlow/examples/).

Read the [docs](https://alex-fir-it.github.io/FennFlow/) to learn more about working with
FennFlow.

Read the [API Reference](https://alex-fir-it.github.io/FennFlow/api/)  to understand FennFlow’s interface.

Learn how to utilize [llms](https://alex-fir-it.github.io/FennFlow/llms) with FennFlow. 
