fast-feature 0.0.1__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.
- fast_feature-0.0.1/PKG-INFO +67 -0
- fast_feature-0.0.1/README.md +27 -0
- fast_feature-0.0.1/pyproject.toml +64 -0
- fast_feature-0.0.1/src/fast_feature/server/__init__.py +7 -0
- fast_feature-0.0.1/src/fast_feature/server/app.py +28 -0
- fast_feature-0.0.1/src/fast_feature/server/cli.py +30 -0
- fast_feature-0.0.1/src/fast_feature/server/py.typed +0 -0
- fast_feature-0.0.1/src/fast_feature/server/repository_factory.py +21 -0
- fast_feature-0.0.1/src/fast_feature/server/settings.py +16 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fast-feature
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A lightweight, async, OpenFeature-compatible (OFREP) feature flag server.
|
|
5
|
+
Keywords: feature-flags,openfeature,ofrep,json-logic,fastapi,async
|
|
6
|
+
Author: byunjuneseok
|
|
7
|
+
Author-email: byunjuneseok <byunjuneseok@gmail.com>
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Framework :: FastAPI
|
|
11
|
+
Classifier: Framework :: AsyncIO
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Dist: fast-feature-core==0.0.1
|
|
21
|
+
Requires-Dist: fast-feature-engine==0.0.1
|
|
22
|
+
Requires-Dist: fast-feature-ofrep==0.0.1
|
|
23
|
+
Requires-Dist: fast-feature-storage-inmemory==0.0.1
|
|
24
|
+
Requires-Dist: pydantic-settings>=2.0
|
|
25
|
+
Requires-Dist: fast-feature-admin==0.0.1 ; extra == 'admin'
|
|
26
|
+
Requires-Dist: fast-feature-storage-postgresql==0.0.1 ; extra == 'all'
|
|
27
|
+
Requires-Dist: fast-feature-admin==0.0.1 ; extra == 'all'
|
|
28
|
+
Requires-Dist: uvicorn[standard]>=0.27 ; extra == 'all'
|
|
29
|
+
Requires-Dist: fast-feature-storage-postgresql==0.0.1 ; extra == 'postgresql'
|
|
30
|
+
Requires-Dist: uvicorn[standard]>=0.27 ; extra == 'standalone'
|
|
31
|
+
Requires-Python: >=3.10
|
|
32
|
+
Project-URL: Homepage, https://github.com/byunjuneseok/fast-feature
|
|
33
|
+
Project-URL: Repository, https://github.com/byunjuneseok/fast-feature
|
|
34
|
+
Project-URL: Issues, https://github.com/byunjuneseok/fast-feature/issues
|
|
35
|
+
Provides-Extra: admin
|
|
36
|
+
Provides-Extra: all
|
|
37
|
+
Provides-Extra: postgresql
|
|
38
|
+
Provides-Extra: standalone
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# fast-feature
|
|
42
|
+
|
|
43
|
+
The umbrella distribution for [fast-feature](https://github.com/byunjuneseok/fast-feature):
|
|
44
|
+
an async, OpenFeature-compatible (OFREP) feature flag server.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install "fast-feature[standalone]" # + uvicorn, to run the server
|
|
48
|
+
pip install "fast-feature[postgresql]" # + PostgreSQL backend
|
|
49
|
+
pip install "fast-feature[admin]" # + admin console
|
|
50
|
+
pip install "fast-feature[all]"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Run it:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
FAST_FEATURE_BACKEND=inmemory fast-feature serve --host 0.0.0.0 --port 8000
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or embed it:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from fast_feature.server import Application, Settings
|
|
63
|
+
|
|
64
|
+
app = Application.create(Settings(admin=True))
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
See the [project README](https://github.com/byunjuneseok/fast-feature) for details.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# fast-feature
|
|
2
|
+
|
|
3
|
+
The umbrella distribution for [fast-feature](https://github.com/byunjuneseok/fast-feature):
|
|
4
|
+
an async, OpenFeature-compatible (OFREP) feature flag server.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install "fast-feature[standalone]" # + uvicorn, to run the server
|
|
8
|
+
pip install "fast-feature[postgresql]" # + PostgreSQL backend
|
|
9
|
+
pip install "fast-feature[admin]" # + admin console
|
|
10
|
+
pip install "fast-feature[all]"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run it:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
FAST_FEATURE_BACKEND=inmemory fast-feature serve --host 0.0.0.0 --port 8000
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or embed it:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from fast_feature.server import Application, Settings
|
|
23
|
+
|
|
24
|
+
app = Application.create(Settings(admin=True))
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
See the [project README](https://github.com/byunjuneseok/fast-feature) for details.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "fast-feature"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "A lightweight, async, OpenFeature-compatible (OFREP) feature flag server."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "Apache-2.0"
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "byunjuneseok", email = "byunjuneseok@gmail.com" },
|
|
10
|
+
]
|
|
11
|
+
keywords = ["feature-flags", "openfeature", "ofrep", "json-logic", "fastapi", "async"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Framework :: FastAPI",
|
|
15
|
+
"Framework :: AsyncIO",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: Apache Software License",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"fast-feature-core==0.0.1",
|
|
27
|
+
"fast-feature-engine==0.0.1",
|
|
28
|
+
"fast-feature-ofrep==0.0.1",
|
|
29
|
+
"fast-feature-storage-inmemory==0.0.1",
|
|
30
|
+
"pydantic-settings>=2.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
postgresql = ["fast-feature-storage-postgresql==0.0.1"]
|
|
35
|
+
admin = ["fast-feature-admin==0.0.1"]
|
|
36
|
+
standalone = ["uvicorn[standard]>=0.27"]
|
|
37
|
+
all = [
|
|
38
|
+
"fast-feature-storage-postgresql==0.0.1",
|
|
39
|
+
"fast-feature-admin==0.0.1",
|
|
40
|
+
"uvicorn[standard]>=0.27",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
fast-feature = "fast_feature.server.cli:Cli.run"
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://github.com/byunjuneseok/fast-feature"
|
|
48
|
+
Repository = "https://github.com/byunjuneseok/fast-feature"
|
|
49
|
+
Issues = "https://github.com/byunjuneseok/fast-feature/issues"
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = ["uv_build>=0.11.17,<0.12.0"]
|
|
53
|
+
build-backend = "uv_build"
|
|
54
|
+
|
|
55
|
+
[tool.uv.build-backend]
|
|
56
|
+
module-name = "fast_feature.server"
|
|
57
|
+
|
|
58
|
+
[tool.uv.sources]
|
|
59
|
+
fast-feature-core = { workspace = true }
|
|
60
|
+
fast-feature-engine = { workspace = true }
|
|
61
|
+
fast-feature-ofrep = { workspace = true }
|
|
62
|
+
fast-feature-storage-inmemory = { workspace = true }
|
|
63
|
+
fast-feature-storage-postgresql = { workspace = true }
|
|
64
|
+
fast-feature-admin = { workspace = true }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from fastapi import FastAPI
|
|
4
|
+
|
|
5
|
+
from fast_feature.ofrep import OfrepRouter
|
|
6
|
+
|
|
7
|
+
from .repository_factory import RepositoryFactory
|
|
8
|
+
from .settings import Settings
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Application:
|
|
12
|
+
"""Composition root: wires settings -> repository -> routers into a FastAPI app."""
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def create(cls, settings: Settings | None = None) -> FastAPI:
|
|
16
|
+
resolved = settings or Settings()
|
|
17
|
+
repository = RepositoryFactory.from_settings(resolved)
|
|
18
|
+
|
|
19
|
+
app = FastAPI(title="fast-feature")
|
|
20
|
+
app.include_router(OfrepRouter.build(repository))
|
|
21
|
+
|
|
22
|
+
if resolved.admin:
|
|
23
|
+
# Imported lazily so the admin distribution is only needed when enabled.
|
|
24
|
+
from fast_feature.admin import AdminRouter
|
|
25
|
+
|
|
26
|
+
app.include_router(AdminRouter.build(repository), prefix=resolved.admin_prefix)
|
|
27
|
+
|
|
28
|
+
return app
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
|
|
6
|
+
from .app import Application
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Cli:
|
|
10
|
+
"""The ``fast-feature`` command-line entry point."""
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def run(cls, argv: Sequence[str] | None = None) -> None:
|
|
14
|
+
parser = argparse.ArgumentParser(prog="fast-feature")
|
|
15
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
16
|
+
serve = subparsers.add_parser("serve", help="Run the OFREP server.")
|
|
17
|
+
serve.add_argument("--host", default="127.0.0.1")
|
|
18
|
+
serve.add_argument("--port", type=int, default=8000)
|
|
19
|
+
|
|
20
|
+
args = parser.parse_args(argv)
|
|
21
|
+
if args.command == "serve":
|
|
22
|
+
cls._serve(args.host, args.port)
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def _serve(host: str, port: int) -> None:
|
|
26
|
+
try:
|
|
27
|
+
import uvicorn
|
|
28
|
+
except ImportError as exc: # pragma: no cover
|
|
29
|
+
raise SystemExit("Install fast-feature[standalone] to run the server.") from exc
|
|
30
|
+
uvicorn.run(Application.create(), host=host, port=port)
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from fast_feature.core import FlagRepository
|
|
4
|
+
from fast_feature.storage.inmemory import InMemoryFlagRepository
|
|
5
|
+
|
|
6
|
+
from .settings import Settings
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RepositoryFactory:
|
|
10
|
+
"""Builds the configured ``FlagRepository`` for the standalone server."""
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def from_settings(settings: Settings) -> FlagRepository:
|
|
14
|
+
if settings.backend == "postgresql":
|
|
15
|
+
if not settings.database_url:
|
|
16
|
+
raise ValueError("FAST_FEATURE_DATABASE_URL is required for the postgresql backend")
|
|
17
|
+
# Imported lazily so the dependency is only needed with the extra.
|
|
18
|
+
from fast_feature.storage.postgresql import PostgresStorage
|
|
19
|
+
|
|
20
|
+
return PostgresStorage.from_dsn(settings.database_url).repository
|
|
21
|
+
return InMemoryFlagRepository()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Settings(BaseSettings):
|
|
9
|
+
"""Standalone-server configuration, read from ``FAST_FEATURE_*`` env vars."""
|
|
10
|
+
|
|
11
|
+
model_config = SettingsConfigDict(env_prefix="FAST_FEATURE_")
|
|
12
|
+
|
|
13
|
+
backend: Literal["inmemory", "postgresql"] = "inmemory"
|
|
14
|
+
database_url: str | None = None
|
|
15
|
+
admin: bool = False
|
|
16
|
+
admin_prefix: str = "/admin"
|