Metadata-Version: 2.1
Name: wexample-storage
Version: 1.2.0
Author-Email: weeger <contact@wexample.com>
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Requires-Dist: wexample-config
Requires-Dist: wexample-helpers>=20.1.0
Requires-Dist: wexample-remote>=1.1.0
Provides-Extra: neo4j
Requires-Dist: neo4j>=5; extra == "neo4j"
Provides-Extra: postgres
Requires-Dist: psycopg2-binary; extra == "postgres"
Requires-Dist: sqlalchemy>=2; extra == "postgres"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: wexample-wallet; extra == "dev"
Description-Content-Type: text/markdown

# storage

Version: 1.2.0

## Files

```python
from wexample_storage import FilesystemStorage

storage = FilesystemStorage(name="uploads", path="/var/app/uploads")
storage.write("report.json", '{"score": 42}')
storage.read_text("report.json")
storage.exists("report.json")
storage.delete("report.json")
```

The directory is created on first write. A key may not leave it: `../x` raises `InvalidStorageKeyException`.

## Vectors

```python
from wexample_storage import PostgresVectorStorage

vectors = PostgresVectorStorage(
    database="store", host="localhost", name="vectors", password="...", user="postgres"
)
vectors.save_vector("doc-1", "chunk-a", [0.1, 0.8, ...], "The text the vector was made from")
vectors.search_vectors("doc-1", query_vector, limit=5, max_distance=0.4)  # closest first
vectors.get_vector_keys("doc-1")
vectors.delete_vectors("doc-1")
```

Vectors are grouped in namespaces, one per document for instance. The table (`wexample_storage_vector` unless `table` says otherwise) and the pgvector extension are created on first use; the column has no fixed dimension, so each embedding model keeps its own. Needs the `postgres` extra.

## Graphs

```python
from wexample_storage import Neo4jGraphStorage

graph = Neo4jGraphStorage(name="graph", url="bolt://localhost:7687", user="neo4j", password="...")
graph.run_query("MATCH (p:Player) RETURN p.name AS name")  # [{"name": ...}, ...]
```

Needs the `neo4j` extra.

## Choosing a storage

```python
from wexample_storage import StorageRegistry

registry = StorageRegistry([uploads, vectors, graph])
registry.get_for_capability("vectors")   # the first storage accepting it
registry.check_all()                      # statuses, as any remote registry
```

A storage accepts the capabilities of its kind unless given others: `FilesystemStorage(capabilities=["archives"], ...)` takes archives only. Without a storage for a capability, `NoStorageForCapabilityException` names those registered.

## From configuration

```python
from wexample_storage.config_option.storages_config_option import StoragesConfigOption

storages = StoragesConfigOption(
    value=[
        {"name": "files", "type": "filesystem", "path": "/var/app/files"},
        {"name": "vectors", "type": "postgres", "credential": "store", "table": "vectors"},
        {"name": "graph", "type": "neo4j", "credential": "graph"},
    ]
).create_storages(wallet)
```

The configuration names the `wexample-wallet` credential holding a backend's secrets; `PostgresVectorStorage.from_credential()` and `Neo4jGraphStorage.from_credential()` do the same from code. `StoragesConfigOption` is a `wexample-config` option, so an application's own schema can include it. A storage missing what its type needs raises `InvalidStorageConfigException`.

## Table of Contents

- [Files](#files)
- [Vectors](#vectors)
- [Graphs](#graphs)
- [Choosing a storage](#choosing-a-storage)
- [From configuration](#from-configuration)
- [Installation](#installation)
- [Tests](#tests)
- [Architecture](#architecture)
- [Integration in the Suite](#integration-in-the-suite)
- [Dependencies](#dependencies)
- [Versioning & Compatibility Policy](#versioning--compatibility-policy)
- [License](#license)
- [About us](#about-us)
- [Known Limitations & Roadmap](#known-limitations--roadmap)
- [Status & Compatibility](#status--compatibility)
- [Useful Links](#useful-links)
- [Migration Notes](#migration-notes)

## Installation

```bash
pip install wexample-storage
```

Requires Python >=3.10.

## Tests

This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.

### Installation

First, install the required testing dependencies:
```bash
.venv/bin/python -m pip install pytest pytest-cov
```

### Basic Usage

Run all tests with coverage:
```bash
.venv/bin/python -m pytest --cov --cov-report=html
```

### Common Commands
```bash
# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module

# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing

# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html

# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html

# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
```

### Viewing HTML Reports

After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.

### Coverage Threshold

To enforce a minimum coverage percentage:
```bash
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
```

This will cause the test suite to fail if coverage drops below 80%.

## Architecture

src/wexample_storage/common/abstract_storage.py is a `wexample-remote` remote with a name, a label and capabilities. A storage's capabilities are those given, or else those of its kind (`get_default_capabilities()`), so that a vector storage never accepts files by accident.

Each kind is an abstract class of its own, since a key-value store, a vector index and a graph share nothing but being storages:

- src/wexample_storage/common/abstract_file_storage.py: `write`, `read`, `exists`, `delete`; implemented by src/wexample_storage/common/filesystem_storage.py.
- src/wexample_storage/common/abstract_vector_storage.py: vectors by namespace and key, searched by cosine distance into src/wexample_storage/common/vector_match.py; implemented by src/wexample_storage/common/postgres_vector_storage.py, in raw SQL through SQLAlchemy so that no pgvector binding is needed.
- src/wexample_storage/common/abstract_graph_storage.py: `run_query()`; implemented by src/wexample_storage/common/neo4j_graph_storage.py, whose records come back as plain dicts.

src/wexample_storage/config_option/storages_config_option.py and src/wexample_storage/config_option/storage_config_option.py are the `wexample-config` schema of a list of storages: a name, a type, a path or the name of a wallet credential. They build the storages, taking secrets from the wallet given, so that a configuration file never holds one.

src/wexample_storage/common/storage_registry.py extends the remote registry with the choice by capability. Capability names are in src/wexample_storage/const/capability.py.

Backend libraries are imported inside the methods using them and declared as extras, so that a filesystem-only application installs none. The PostgreSQL and Neo4j tests run only when `WEXAMPLE_STORAGE_TEST_POSTGRES` (`host:port:database:user:password`) or `WEXAMPLE_STORAGE_TEST_NEO4J` (`url|user|password`) point at a server.

## Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

### Related Packages

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.

## Dependencies

- wexample-config: 
- wexample-helpers: >=20.1.0
- wexample-remote: >=1.1.0

## Versioning & Compatibility Policy

Wexample packages follow **Semantic Versioning** (SemVer):

- **MAJOR**: Breaking changes
- **MINOR**: New features, backward compatible
- **PATCH**: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

Free to use in both personal and commercial projects.

## About us

[Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

## Known Limitations & Roadmap

Current limitations and planned features are tracked in the GitHub issues.

See the [project roadmap](https://github.com/wexample/python-storage/issues) for upcoming features and improvements.

## Status & Compatibility

**Maturity**: Production-ready

**Python Support**: >=3.10

**OS Support**: Linux, macOS, Windows

**Status**: Actively maintained

## Useful Links

- **Homepage**: https://github.com/wexample/python-storage
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
- **Issue Tracker**: https://github.com/wexample/python-storage/issues
- **Discussions**: https://github.com/wexample/python-storage/discussions
- **PyPI**: [pypi.org/project/wexample-storage](https://pypi.org/project/wexample-storage/)

## Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.
