servicephilosophy 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Josh Martin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ prune tests
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.4
2
+ Name: servicephilosophy
3
+ Version: 0.1.0
4
+ Summary: Typed factory-aware base for service and repository components without a domain model.
5
+ Author-email: Josh Martin <denverprogrammer@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/SignalSafeSoftware/servicephilosophy
8
+ Project-URL: Repository, https://github.com/SignalSafeSoftware/servicephilosophy
9
+ Project-URL: Documentation, https://github.com/SignalSafeSoftware/servicephilosophy#readme
10
+ Project-URL: Issues, https://github.com/SignalSafeSoftware/servicephilosophy/issues
11
+ Keywords: repository-pattern,service-layer,factory,typing
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: <4.0,>=3.12
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=8; extra == "dev"
23
+ Requires-Dist: pytest-cov>=6; extra == "dev"
24
+ Requires-Dist: ruff>=0.15; extra == "dev"
25
+ Requires-Dist: mypy>=1.11; extra == "dev"
26
+ Requires-Dist: build>=1.2; extra == "dev"
27
+ Requires-Dist: twine>=5; extra == "dev"
28
+ Requires-Dist: bandit>=1.7; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # servicePhilosophy
32
+
33
+ A small typed foundation for factory-aware repository-style components.
34
+
35
+ | | |
36
+ |---|---|
37
+ | **Python** | 3.12+ |
38
+ | **Runtime deps** | none |
39
+ | **License** | MIT |
40
+
41
+ ## Core idea
42
+
43
+ ```text
44
+ ServiceRepository[FactoryT]
45
+ = a neutral base class for objects that need factory access.
46
+ It does not require a model.
47
+ It does not know about SQL, HTTP, controllers, or frameworks.
48
+ ```
49
+
50
+ `ServiceRepository` stores an optional factory and exposes it through:
51
+
52
+ - **`factory`** — returns the factory, or raises `FactoryRequiredError` when missing
53
+ - **`maybe_factory`** — returns the factory or `None`
54
+ - **`has_factory`** — `True` when a factory was provided at construction
55
+
56
+ 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.
57
+
58
+ ## What this is (and is not)
59
+
60
+ - **`ServiceRepository` is not a SQL repository.**
61
+ - **`ServiceRepository` is not an API client.**
62
+ - It is a **shared factory-aware base**.
63
+ - **[sqlPhilosophy](https://github.com/SignalSafeSoftware/sqlphilosophy)** can extend it with model-bound persistence.
64
+ - **apiPhilosophy** can extend it with HTTP/resource clients.
65
+ - **Application service repositories** can extend it directly for business logic with no model at all.
66
+
67
+ This package has zero runtime dependencies. It does not include SQLAlchemy, HTTP clients, FastAPI, Pydantic, or Django.
68
+
69
+ ## Basic service repository
70
+
71
+ ```python
72
+ from servicephilosophy import ServiceRepository
73
+
74
+
75
+ class ServiceFactory:
76
+ def greeting(self) -> str:
77
+ return "hello"
78
+
79
+
80
+ class GreetingService(ServiceRepository[ServiceFactory]):
81
+ def greet(self) -> str:
82
+ return self.factory.greeting()
83
+ ```
84
+
85
+ ## SQL specialization in another package
86
+
87
+ ```python
88
+ from typing import Generic, TypeVar
89
+
90
+ from servicephilosophy import ServiceRepository
91
+
92
+ ModelT = TypeVar("ModelT")
93
+ FactoryT = TypeVar("FactoryT")
94
+
95
+
96
+ class BaseRepository(ServiceRepository[FactoryT], Generic[ModelT, FactoryT]):
97
+ model: type[ModelT]
98
+ ```
99
+
100
+ ## API specialization in another package
101
+
102
+ ```python
103
+ from typing import Generic, TypeVar
104
+
105
+ from servicephilosophy import ServiceRepository
106
+
107
+ ResourceT = TypeVar("ResourceT")
108
+ FactoryT = TypeVar("FactoryT")
109
+
110
+
111
+ class BaseApiRepository(ServiceRepository[FactoryT], Generic[ResourceT, FactoryT]):
112
+ pass
113
+ ```
114
+
115
+ ## Business logic with no model
116
+
117
+ ```python
118
+ from servicephilosophy import ServiceRepository
119
+
120
+
121
+ class PermissionServiceRepository(ServiceRepository[ServiceFactory]):
122
+ def has_permission(self, actor_id: int, permission: str) -> bool:
123
+ return True
124
+ ```
125
+
126
+ ## Recommended ecosystem
127
+
128
+ ```text
129
+ servicePhilosophy
130
+ ServiceRepository[FactoryT]
131
+
132
+ sqlPhilosophy
133
+ BaseRepository[ModelT, FactoryT]
134
+
135
+ apiPhilosophy
136
+ BaseApiRepository[ResourceT, FactoryT]
137
+
138
+ application
139
+ PermissionServiceRepository(ServiceRepository[ServiceFactory])
140
+ ```
141
+
142
+ Each layer adds its own concern. `servicePhilosophy` only handles factory wiring; specialization lives in the package or application that needs it.
143
+
144
+ ## Install
145
+
146
+ ```bash
147
+ pip install servicephilosophy
148
+ ```
149
+
150
+ Development:
151
+
152
+ ```bash
153
+ uv sync --extra dev
154
+ uv run pytest
155
+ uv run ruff check src tests
156
+ uv run mypy src
157
+ ```
158
+
159
+ ## Public API
160
+
161
+ ```python
162
+ from servicephilosophy import (
163
+ FactoryRequiredError,
164
+ RepositoryFactoryProtocol,
165
+ ServiceRepository,
166
+ ServiceRepositoryProtocol,
167
+ )
168
+ ```
169
+
170
+ Or import from submodules:
171
+
172
+ ```python
173
+ from servicephilosophy.repository import ServiceRepository
174
+ from servicephilosophy.protocols import RepositoryFactoryProtocol, ServiceRepositoryProtocol
175
+ from servicephilosophy.exceptions import FactoryRequiredError
176
+ ```
@@ -0,0 +1,146 @@
1
+ # servicePhilosophy
2
+
3
+ A small typed foundation for factory-aware repository-style components.
4
+
5
+ | | |
6
+ |---|---|
7
+ | **Python** | 3.12+ |
8
+ | **Runtime deps** | none |
9
+ | **License** | MIT |
10
+
11
+ ## Core idea
12
+
13
+ ```text
14
+ ServiceRepository[FactoryT]
15
+ = a neutral base class for objects that need factory access.
16
+ It does not require a model.
17
+ It does not know about SQL, HTTP, controllers, or frameworks.
18
+ ```
19
+
20
+ `ServiceRepository` stores an optional factory and exposes it through:
21
+
22
+ - **`factory`** — returns the factory, or raises `FactoryRequiredError` when missing
23
+ - **`maybe_factory`** — returns the factory or `None`
24
+ - **`has_factory`** — `True` when a factory was provided at construction
25
+
26
+ 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.
27
+
28
+ ## What this is (and is not)
29
+
30
+ - **`ServiceRepository` is not a SQL repository.**
31
+ - **`ServiceRepository` is not an API client.**
32
+ - It is a **shared factory-aware base**.
33
+ - **[sqlPhilosophy](https://github.com/SignalSafeSoftware/sqlphilosophy)** can extend it with model-bound persistence.
34
+ - **apiPhilosophy** can extend it with HTTP/resource clients.
35
+ - **Application service repositories** can extend it directly for business logic with no model at all.
36
+
37
+ This package has zero runtime dependencies. It does not include SQLAlchemy, HTTP clients, FastAPI, Pydantic, or Django.
38
+
39
+ ## Basic service repository
40
+
41
+ ```python
42
+ from servicephilosophy import ServiceRepository
43
+
44
+
45
+ class ServiceFactory:
46
+ def greeting(self) -> str:
47
+ return "hello"
48
+
49
+
50
+ class GreetingService(ServiceRepository[ServiceFactory]):
51
+ def greet(self) -> str:
52
+ return self.factory.greeting()
53
+ ```
54
+
55
+ ## SQL specialization in another package
56
+
57
+ ```python
58
+ from typing import Generic, TypeVar
59
+
60
+ from servicephilosophy import ServiceRepository
61
+
62
+ ModelT = TypeVar("ModelT")
63
+ FactoryT = TypeVar("FactoryT")
64
+
65
+
66
+ class BaseRepository(ServiceRepository[FactoryT], Generic[ModelT, FactoryT]):
67
+ model: type[ModelT]
68
+ ```
69
+
70
+ ## API specialization in another package
71
+
72
+ ```python
73
+ from typing import Generic, TypeVar
74
+
75
+ from servicephilosophy import ServiceRepository
76
+
77
+ ResourceT = TypeVar("ResourceT")
78
+ FactoryT = TypeVar("FactoryT")
79
+
80
+
81
+ class BaseApiRepository(ServiceRepository[FactoryT], Generic[ResourceT, FactoryT]):
82
+ pass
83
+ ```
84
+
85
+ ## Business logic with no model
86
+
87
+ ```python
88
+ from servicephilosophy import ServiceRepository
89
+
90
+
91
+ class PermissionServiceRepository(ServiceRepository[ServiceFactory]):
92
+ def has_permission(self, actor_id: int, permission: str) -> bool:
93
+ return True
94
+ ```
95
+
96
+ ## Recommended ecosystem
97
+
98
+ ```text
99
+ servicePhilosophy
100
+ ServiceRepository[FactoryT]
101
+
102
+ sqlPhilosophy
103
+ BaseRepository[ModelT, FactoryT]
104
+
105
+ apiPhilosophy
106
+ BaseApiRepository[ResourceT, FactoryT]
107
+
108
+ application
109
+ PermissionServiceRepository(ServiceRepository[ServiceFactory])
110
+ ```
111
+
112
+ Each layer adds its own concern. `servicePhilosophy` only handles factory wiring; specialization lives in the package or application that needs it.
113
+
114
+ ## Install
115
+
116
+ ```bash
117
+ pip install servicephilosophy
118
+ ```
119
+
120
+ Development:
121
+
122
+ ```bash
123
+ uv sync --extra dev
124
+ uv run pytest
125
+ uv run ruff check src tests
126
+ uv run mypy src
127
+ ```
128
+
129
+ ## Public API
130
+
131
+ ```python
132
+ from servicephilosophy import (
133
+ FactoryRequiredError,
134
+ RepositoryFactoryProtocol,
135
+ ServiceRepository,
136
+ ServiceRepositoryProtocol,
137
+ )
138
+ ```
139
+
140
+ Or import from submodules:
141
+
142
+ ```python
143
+ from servicephilosophy.repository import ServiceRepository
144
+ from servicephilosophy.protocols import RepositoryFactoryProtocol, ServiceRepositoryProtocol
145
+ from servicephilosophy.exceptions import FactoryRequiredError
146
+ ```
@@ -0,0 +1,93 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "servicephilosophy"
7
+ version = "0.1.0"
8
+ description = "Typed factory-aware base for service and repository components without a domain model."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12,<4.0"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ { name = "Josh Martin", email = "denverprogrammer@gmail.com" }
15
+ ]
16
+ keywords = ["repository-pattern", "service-layer", "factory", "typing"]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Typing :: Typed",
24
+ ]
25
+ dependencies = []
26
+
27
+ [project.optional-dependencies]
28
+ dev = [
29
+ "pytest>=8",
30
+ "pytest-cov>=6",
31
+ "ruff>=0.15",
32
+ "mypy>=1.11",
33
+ "build>=1.2",
34
+ "twine>=5",
35
+ "bandit>=1.7",
36
+ ]
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/SignalSafeSoftware/servicephilosophy"
40
+ Repository = "https://github.com/SignalSafeSoftware/servicephilosophy"
41
+ Documentation = "https://github.com/SignalSafeSoftware/servicephilosophy#readme"
42
+ Issues = "https://github.com/SignalSafeSoftware/servicephilosophy/issues"
43
+
44
+ [tool.setuptools.packages.find]
45
+ where = ["src"]
46
+
47
+ [tool.setuptools.package-data]
48
+ servicephilosophy = ["py.typed"]
49
+
50
+ [tool.pytest.ini_options]
51
+ testpaths = ["tests"]
52
+ addopts = "--cov=servicephilosophy --cov-report=term-missing --cov-fail-under=100"
53
+
54
+ [tool.coverage.run]
55
+ source = ["servicephilosophy"]
56
+
57
+ [tool.coverage.report]
58
+ fail_under = 100
59
+ show_missing = true
60
+
61
+ [tool.mypy]
62
+ python_version = "3.12"
63
+ warn_unused_ignores = true
64
+ strict = true
65
+
66
+ [tool.ruff]
67
+ target-version = "py312"
68
+ line-length = 120
69
+ src = ["src", "tests"]
70
+
71
+ [tool.ruff.lint]
72
+ select = [
73
+ "E",
74
+ "F",
75
+ "W",
76
+ "I",
77
+ "B",
78
+ "UP",
79
+ "SIM",
80
+ "PT",
81
+ "RUF",
82
+ ]
83
+ ignore = [
84
+ "E203",
85
+ ]
86
+
87
+ [tool.ruff.lint.per-file-ignores]
88
+ "tests/**/*.py" = [
89
+ "PT011",
90
+ ]
91
+
92
+ [tool.uv]
93
+ package = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,18 @@
1
+ """Factory-aware service repository foundation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from servicephilosophy.exceptions import FactoryRequiredError, ServicePhilosophyError
6
+ from servicephilosophy.protocols import RepositoryFactoryProtocol, ServiceRepositoryProtocol
7
+ from servicephilosophy.repository import ServiceRepository
8
+
9
+ __all__ = [
10
+ "FactoryRequiredError",
11
+ "RepositoryFactoryProtocol",
12
+ "ServicePhilosophyError",
13
+ "ServiceRepository",
14
+ "ServiceRepositoryProtocol",
15
+ "__version__",
16
+ ]
17
+
18
+ __version__ = "0.1.0"
@@ -0,0 +1,9 @@
1
+ """Shared exceptions for servicephilosophy."""
2
+
3
+
4
+ class ServicePhilosophyError(Exception):
5
+ """Base error for servicephilosophy."""
6
+
7
+
8
+ class FactoryRequiredError(ServicePhilosophyError):
9
+ """Raised when an operation requires a factory but none was configured."""
@@ -0,0 +1,29 @@
1
+ """Protocols for factory-aware service repositories."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Protocol, TypeVar
6
+
7
+ FactoryT = TypeVar("FactoryT", covariant=True)
8
+
9
+
10
+ class ServiceRepositoryProtocol(Protocol[FactoryT]):
11
+ """Structural typing surface for factory-aware repositories."""
12
+
13
+ @property
14
+ def factory(self) -> FactoryT: ...
15
+
16
+ @property
17
+ def maybe_factory(self) -> FactoryT | None: ...
18
+
19
+ @property
20
+ def has_factory(self) -> bool: ...
21
+
22
+
23
+ class RepositoryFactoryProtocol(Protocol):
24
+ """Marker protocol for repository-scoped factories.
25
+
26
+ Intentionally empty so downstream packages can extend it with
27
+ SQL-, API-, or application-specific methods without coupling this
28
+ package to those concerns.
29
+ """
File without changes
@@ -0,0 +1,33 @@
1
+ """Factory-aware base class for service repositories without a domain model."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abc import ABC
6
+
7
+ from servicephilosophy.exceptions import FactoryRequiredError
8
+
9
+
10
+ class ServiceRepository[FactoryT](ABC): # noqa: B024 — extension point for service subclasses
11
+ """Neutral factory-aware base for service-layer repositories.
12
+
13
+ Unlike data repositories, this type does **not** bind to a model or
14
+ persistence backend. Subclasses add domain methods and access the shared
15
+ factory through ``factory``, ``maybe_factory``, or ``has_factory``.
16
+ """
17
+
18
+ def __init__(self, factory: FactoryT | None = None) -> None:
19
+ self._factory: FactoryT | None = factory
20
+
21
+ @property
22
+ def factory(self) -> FactoryT:
23
+ if self._factory is None:
24
+ raise FactoryRequiredError("factory is required for this operation")
25
+ return self._factory
26
+
27
+ @property
28
+ def maybe_factory(self) -> FactoryT | None:
29
+ return self._factory
30
+
31
+ @property
32
+ def has_factory(self) -> bool:
33
+ return self._factory is not None
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.4
2
+ Name: servicephilosophy
3
+ Version: 0.1.0
4
+ Summary: Typed factory-aware base for service and repository components without a domain model.
5
+ Author-email: Josh Martin <denverprogrammer@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/SignalSafeSoftware/servicephilosophy
8
+ Project-URL: Repository, https://github.com/SignalSafeSoftware/servicephilosophy
9
+ Project-URL: Documentation, https://github.com/SignalSafeSoftware/servicephilosophy#readme
10
+ Project-URL: Issues, https://github.com/SignalSafeSoftware/servicephilosophy/issues
11
+ Keywords: repository-pattern,service-layer,factory,typing
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: <4.0,>=3.12
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=8; extra == "dev"
23
+ Requires-Dist: pytest-cov>=6; extra == "dev"
24
+ Requires-Dist: ruff>=0.15; extra == "dev"
25
+ Requires-Dist: mypy>=1.11; extra == "dev"
26
+ Requires-Dist: build>=1.2; extra == "dev"
27
+ Requires-Dist: twine>=5; extra == "dev"
28
+ Requires-Dist: bandit>=1.7; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # servicePhilosophy
32
+
33
+ A small typed foundation for factory-aware repository-style components.
34
+
35
+ | | |
36
+ |---|---|
37
+ | **Python** | 3.12+ |
38
+ | **Runtime deps** | none |
39
+ | **License** | MIT |
40
+
41
+ ## Core idea
42
+
43
+ ```text
44
+ ServiceRepository[FactoryT]
45
+ = a neutral base class for objects that need factory access.
46
+ It does not require a model.
47
+ It does not know about SQL, HTTP, controllers, or frameworks.
48
+ ```
49
+
50
+ `ServiceRepository` stores an optional factory and exposes it through:
51
+
52
+ - **`factory`** — returns the factory, or raises `FactoryRequiredError` when missing
53
+ - **`maybe_factory`** — returns the factory or `None`
54
+ - **`has_factory`** — `True` when a factory was provided at construction
55
+
56
+ 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.
57
+
58
+ ## What this is (and is not)
59
+
60
+ - **`ServiceRepository` is not a SQL repository.**
61
+ - **`ServiceRepository` is not an API client.**
62
+ - It is a **shared factory-aware base**.
63
+ - **[sqlPhilosophy](https://github.com/SignalSafeSoftware/sqlphilosophy)** can extend it with model-bound persistence.
64
+ - **apiPhilosophy** can extend it with HTTP/resource clients.
65
+ - **Application service repositories** can extend it directly for business logic with no model at all.
66
+
67
+ This package has zero runtime dependencies. It does not include SQLAlchemy, HTTP clients, FastAPI, Pydantic, or Django.
68
+
69
+ ## Basic service repository
70
+
71
+ ```python
72
+ from servicephilosophy import ServiceRepository
73
+
74
+
75
+ class ServiceFactory:
76
+ def greeting(self) -> str:
77
+ return "hello"
78
+
79
+
80
+ class GreetingService(ServiceRepository[ServiceFactory]):
81
+ def greet(self) -> str:
82
+ return self.factory.greeting()
83
+ ```
84
+
85
+ ## SQL specialization in another package
86
+
87
+ ```python
88
+ from typing import Generic, TypeVar
89
+
90
+ from servicephilosophy import ServiceRepository
91
+
92
+ ModelT = TypeVar("ModelT")
93
+ FactoryT = TypeVar("FactoryT")
94
+
95
+
96
+ class BaseRepository(ServiceRepository[FactoryT], Generic[ModelT, FactoryT]):
97
+ model: type[ModelT]
98
+ ```
99
+
100
+ ## API specialization in another package
101
+
102
+ ```python
103
+ from typing import Generic, TypeVar
104
+
105
+ from servicephilosophy import ServiceRepository
106
+
107
+ ResourceT = TypeVar("ResourceT")
108
+ FactoryT = TypeVar("FactoryT")
109
+
110
+
111
+ class BaseApiRepository(ServiceRepository[FactoryT], Generic[ResourceT, FactoryT]):
112
+ pass
113
+ ```
114
+
115
+ ## Business logic with no model
116
+
117
+ ```python
118
+ from servicephilosophy import ServiceRepository
119
+
120
+
121
+ class PermissionServiceRepository(ServiceRepository[ServiceFactory]):
122
+ def has_permission(self, actor_id: int, permission: str) -> bool:
123
+ return True
124
+ ```
125
+
126
+ ## Recommended ecosystem
127
+
128
+ ```text
129
+ servicePhilosophy
130
+ ServiceRepository[FactoryT]
131
+
132
+ sqlPhilosophy
133
+ BaseRepository[ModelT, FactoryT]
134
+
135
+ apiPhilosophy
136
+ BaseApiRepository[ResourceT, FactoryT]
137
+
138
+ application
139
+ PermissionServiceRepository(ServiceRepository[ServiceFactory])
140
+ ```
141
+
142
+ Each layer adds its own concern. `servicePhilosophy` only handles factory wiring; specialization lives in the package or application that needs it.
143
+
144
+ ## Install
145
+
146
+ ```bash
147
+ pip install servicephilosophy
148
+ ```
149
+
150
+ Development:
151
+
152
+ ```bash
153
+ uv sync --extra dev
154
+ uv run pytest
155
+ uv run ruff check src tests
156
+ uv run mypy src
157
+ ```
158
+
159
+ ## Public API
160
+
161
+ ```python
162
+ from servicephilosophy import (
163
+ FactoryRequiredError,
164
+ RepositoryFactoryProtocol,
165
+ ServiceRepository,
166
+ ServiceRepositoryProtocol,
167
+ )
168
+ ```
169
+
170
+ Or import from submodules:
171
+
172
+ ```python
173
+ from servicephilosophy.repository import ServiceRepository
174
+ from servicephilosophy.protocols import RepositoryFactoryProtocol, ServiceRepositoryProtocol
175
+ from servicephilosophy.exceptions import FactoryRequiredError
176
+ ```
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ src/servicephilosophy/__init__.py
6
+ src/servicephilosophy/exceptions.py
7
+ src/servicephilosophy/protocols.py
8
+ src/servicephilosophy/py.typed
9
+ src/servicephilosophy/repository.py
10
+ src/servicephilosophy.egg-info/PKG-INFO
11
+ src/servicephilosophy.egg-info/SOURCES.txt
12
+ src/servicephilosophy.egg-info/dependency_links.txt
13
+ src/servicephilosophy.egg-info/requires.txt
14
+ src/servicephilosophy.egg-info/top_level.txt
@@ -0,0 +1,9 @@
1
+
2
+ [dev]
3
+ pytest>=8
4
+ pytest-cov>=6
5
+ ruff>=0.15
6
+ mypy>=1.11
7
+ build>=1.2
8
+ twine>=5
9
+ bandit>=1.7
@@ -0,0 +1 @@
1
+ servicephilosophy