Metadata-Version: 2.4
Name: servicephilosophy
Version: 0.1.0
Summary: Typed factory-aware base for service and repository components without a domain model.
Author-email: Josh Martin <denverprogrammer@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/SignalSafeSoftware/servicephilosophy
Project-URL: Repository, https://github.com/SignalSafeSoftware/servicephilosophy
Project-URL: Documentation, https://github.com/SignalSafeSoftware/servicephilosophy#readme
Project-URL: Issues, https://github.com/SignalSafeSoftware/servicephilosophy/issues
Keywords: repository-pattern,service-layer,factory,typing
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: <4.0,>=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-cov>=6; extra == "dev"
Requires-Dist: ruff>=0.15; extra == "dev"
Requires-Dist: mypy>=1.11; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Requires-Dist: bandit>=1.7; extra == "dev"
Dynamic: license-file

# servicePhilosophy

A small typed foundation for factory-aware repository-style components.

| | |
|---|---|
| **Python** | 3.12+ |
| **Runtime deps** | none |
| **License** | MIT |

## Core idea

```text
ServiceRepository[FactoryT]
= a neutral base class for objects that need factory access.
It does not require a model.
It does not know about SQL, HTTP, controllers, or frameworks.
```

`ServiceRepository` stores an optional factory and exposes it through:

- **`factory`** — returns the factory, or raises `FactoryRequiredError` when missing
- **`maybe_factory`** — returns the factory or `None`
- **`has_factory`** — `True` when a factory was provided at construction

Use **`ServiceRepositoryProtocol`** when you want to type against that shape without inheriting from the base class. Use **`RepositoryFactoryProtocol`** as a minimal marker for factory types that downstream packages extend.

## What this is (and is not)

- **`ServiceRepository` is not a SQL repository.**
- **`ServiceRepository` is not an API client.**
- It is a **shared factory-aware base**.
- **[sqlPhilosophy](https://github.com/SignalSafeSoftware/sqlphilosophy)** can extend it with model-bound persistence.
- **apiPhilosophy** can extend it with HTTP/resource clients.
- **Application service repositories** can extend it directly for business logic with no model at all.

This package has zero runtime dependencies. It does not include SQLAlchemy, HTTP clients, FastAPI, Pydantic, or Django.

## Basic service repository

```python
from servicephilosophy import ServiceRepository


class ServiceFactory:
    def greeting(self) -> str:
        return "hello"


class GreetingService(ServiceRepository[ServiceFactory]):
    def greet(self) -> str:
        return self.factory.greeting()
```

## SQL specialization in another package

```python
from typing import Generic, TypeVar

from servicephilosophy import ServiceRepository

ModelT = TypeVar("ModelT")
FactoryT = TypeVar("FactoryT")


class BaseRepository(ServiceRepository[FactoryT], Generic[ModelT, FactoryT]):
    model: type[ModelT]
```

## API specialization in another package

```python
from typing import Generic, TypeVar

from servicephilosophy import ServiceRepository

ResourceT = TypeVar("ResourceT")
FactoryT = TypeVar("FactoryT")


class BaseApiRepository(ServiceRepository[FactoryT], Generic[ResourceT, FactoryT]):
    pass
```

## Business logic with no model

```python
from servicephilosophy import ServiceRepository


class PermissionServiceRepository(ServiceRepository[ServiceFactory]):
    def has_permission(self, actor_id: int, permission: str) -> bool:
        return True
```

## Recommended ecosystem

```text
servicePhilosophy
  ServiceRepository[FactoryT]

sqlPhilosophy
  BaseRepository[ModelT, FactoryT]

apiPhilosophy
  BaseApiRepository[ResourceT, FactoryT]

application
  PermissionServiceRepository(ServiceRepository[ServiceFactory])
```

Each layer adds its own concern. `servicePhilosophy` only handles factory wiring; specialization lives in the package or application that needs it.

## Install

```bash
pip install servicephilosophy
```

Development:

```bash
uv sync --extra dev
uv run pytest
uv run ruff check src tests
uv run mypy src
```

## Public API

```python
from servicephilosophy import (
    FactoryRequiredError,
    RepositoryFactoryProtocol,
    ServiceRepository,
    ServiceRepositoryProtocol,
)
```

Or import from submodules:

```python
from servicephilosophy.repository import ServiceRepository
from servicephilosophy.protocols import RepositoryFactoryProtocol, ServiceRepositoryProtocol
from servicephilosophy.exceptions import FactoryRequiredError
```
