flowlab 0.1.0__py3-none-any.whl

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.
Files changed (173) hide show
  1. flowlab/__init__.py +109 -0
  2. flowlab/__main__.py +3 -0
  3. flowlab/_cache.py +42 -0
  4. flowlab/_commands.py +101 -0
  5. flowlab/_console.py +37 -0
  6. flowlab/_database.py +64 -0
  7. flowlab/_exceptions.py +31 -0
  8. flowlab/_flowlab.py +454 -0
  9. flowlab/_handlers.py +55 -0
  10. flowlab/_module.py +24 -0
  11. flowlab/_queue.py +27 -0
  12. flowlab/_routing.py +46 -0
  13. flowlab/_settings.py +337 -0
  14. flowlab/_state.py +32 -0
  15. flowlab/modules/__init__.py +0 -0
  16. flowlab/modules/auth/__init__.py +52 -0
  17. flowlab/modules/auth/_api_keys.py +55 -0
  18. flowlab/modules/auth/_commands.py +123 -0
  19. flowlab/modules/auth/_dependencies.py +35 -0
  20. flowlab/modules/auth/_email.py +2 -0
  21. flowlab/modules/auth/_mcp.py +69 -0
  22. flowlab/modules/auth/_models.py +62 -0
  23. flowlab/modules/auth/_routers.py +92 -0
  24. flowlab/modules/auth/_schema.py +27 -0
  25. flowlab/modules/auth/_schemas.py +50 -0
  26. flowlab/modules/auth/_security.py +97 -0
  27. flowlab/modules/auth/_users.py +134 -0
  28. flowlab/modules/auth/migrations/0001_01_01_000000_create_users_table.py +20 -0
  29. flowlab/modules/auth/migrations/0001_01_01_000001_create_api_keys_table.py +25 -0
  30. flowlab/modules/cache/__init__.py +3 -0
  31. flowlab/modules/cache/_cache.py +121 -0
  32. flowlab/modules/cache/adapters/__init__.py +17 -0
  33. flowlab/modules/cache/adapters/_base.py +38 -0
  34. flowlab/modules/cache/adapters/_database.py +107 -0
  35. flowlab/modules/cache/adapters/_memcached.py +57 -0
  36. flowlab/modules/cache/adapters/_redis.py +19 -0
  37. flowlab/modules/cache/adapters/_redis_like.py +55 -0
  38. flowlab/modules/cache/adapters/_shared_memory.py +85 -0
  39. flowlab/modules/cache/adapters/_valkey.py +19 -0
  40. flowlab/modules/db/__init__.py +43 -0
  41. flowlab/modules/db/_exceptions.py +29 -0
  42. flowlab/modules/db/_helpers.py +48 -0
  43. flowlab/modules/db/_json.py +30 -0
  44. flowlab/modules/db/_query_with_params.py +69 -0
  45. flowlab/modules/db/_threading.py +295 -0
  46. flowlab/modules/db/adapters/__init__.py +12 -0
  47. flowlab/modules/db/adapters/_base.py +161 -0
  48. flowlab/modules/db/adapters/_mysql.py +269 -0
  49. flowlab/modules/db/adapters/_postgres.py +610 -0
  50. flowlab/modules/db/adapters/_sqlite.py +364 -0
  51. flowlab/modules/db/database/__init__.py +9 -0
  52. flowlab/modules/db/database/_abc.py +278 -0
  53. flowlab/modules/db/database/_copy.py +149 -0
  54. flowlab/modules/db/database/_db.py +202 -0
  55. flowlab/modules/db/database/_introspection.py +152 -0
  56. flowlab/modules/db/database/_table.py +210 -0
  57. flowlab/modules/db/dialects/__init__.py +13 -0
  58. flowlab/modules/db/dialects/_base.py +213 -0
  59. flowlab/modules/db/dialects/_mysql.py +306 -0
  60. flowlab/modules/db/dialects/_postgres.py +273 -0
  61. flowlab/modules/db/dialects/_sql_dialect.py +1197 -0
  62. flowlab/modules/db/dialects/_sqlite.py +302 -0
  63. flowlab/modules/db/orm/__init__.py +52 -0
  64. flowlab/modules/db/orm/_column.py +30 -0
  65. flowlab/modules/db/orm/_delete.py +222 -0
  66. flowlab/modules/db/orm/_insert.py +290 -0
  67. flowlab/modules/db/orm/_loader.py +168 -0
  68. flowlab/modules/db/orm/_mapper.py +104 -0
  69. flowlab/modules/db/orm/_meta.py +192 -0
  70. flowlab/modules/db/orm/_model.py +9 -0
  71. flowlab/modules/db/orm/_relation.py +212 -0
  72. flowlab/modules/db/orm/_select.py +50 -0
  73. flowlab/modules/db/orm/_tree.py +75 -0
  74. flowlab/modules/db/orm/_update.py +125 -0
  75. flowlab/modules/db/orm/enums/__init__.py +5 -0
  76. flowlab/modules/db/orm/enums/_relation.py +8 -0
  77. flowlab/modules/db/query/__init__.py +41 -0
  78. flowlab/modules/db/query/_alter_table.py +28 -0
  79. flowlab/modules/db/query/_condition.py +20 -0
  80. flowlab/modules/db/query/_condition_group.py +24 -0
  81. flowlab/modules/db/query/_condition_mixin.py +370 -0
  82. flowlab/modules/db/query/_create_index.py +61 -0
  83. flowlab/modules/db/query/_create_table.py +39 -0
  84. flowlab/modules/db/query/_ddl_mixins.py +310 -0
  85. flowlab/modules/db/query/_delete.py +31 -0
  86. flowlab/modules/db/query/_drop_index.py +43 -0
  87. flowlab/modules/db/query/_drop_table.py +31 -0
  88. flowlab/modules/db/query/_having_mixin.py +286 -0
  89. flowlab/modules/db/query/_insert.py +235 -0
  90. flowlab/modules/db/query/_join.py +293 -0
  91. flowlab/modules/db/query/_joins_mixin.py +142 -0
  92. flowlab/modules/db/query/_on_conflict.py +10 -0
  93. flowlab/modules/db/query/_order_by.py +15 -0
  94. flowlab/modules/db/query/_query.py +77 -0
  95. flowlab/modules/db/query/_select.py +79 -0
  96. flowlab/modules/db/query/_simple_mixins.py +159 -0
  97. flowlab/modules/db/query/_union.py +15 -0
  98. flowlab/modules/db/query/_update.py +29 -0
  99. flowlab/modules/db/query/_where_mixin.py +286 -0
  100. flowlab/modules/db/query/ddl/__init__.py +38 -0
  101. flowlab/modules/db/query/ddl/_add_column.py +11 -0
  102. flowlab/modules/db/query/ddl/_add_foreign_key_constraint.py +11 -0
  103. flowlab/modules/db/query/ddl/_add_primary_keys.py +10 -0
  104. flowlab/modules/db/query/ddl/_add_unique_constraint.py +11 -0
  105. flowlab/modules/db/query/ddl/_alter.py +7 -0
  106. flowlab/modules/db/query/ddl/_alter_column.py +11 -0
  107. flowlab/modules/db/query/ddl/_column.py +16 -0
  108. flowlab/modules/db/query/ddl/_constraint.py +7 -0
  109. flowlab/modules/db/query/ddl/_drop_column.py +10 -0
  110. flowlab/modules/db/query/ddl/_drop_constraint.py +10 -0
  111. flowlab/modules/db/query/ddl/_foreign_key_constraint.py +16 -0
  112. flowlab/modules/db/query/ddl/_index.py +10 -0
  113. flowlab/modules/db/query/ddl/_raw_alter.py +10 -0
  114. flowlab/modules/db/query/ddl/_raw_constraint.py +10 -0
  115. flowlab/modules/db/query/ddl/_rename_column.py +11 -0
  116. flowlab/modules/db/query/ddl/_table_description.py +91 -0
  117. flowlab/modules/db/query/ddl/_unique_constraint.py +11 -0
  118. flowlab/modules/db/query/enums/__init__.py +17 -0
  119. flowlab/modules/db/query/enums/_chain.py +6 -0
  120. flowlab/modules/db/query/enums/_condition.py +23 -0
  121. flowlab/modules/db/query/enums/_join.py +10 -0
  122. flowlab/modules/db/query/enums/_order_by_dir.py +6 -0
  123. flowlab/modules/db/query/enums/_referential_action.py +32 -0
  124. flowlab/modules/db/query/enums/_type.py +10 -0
  125. flowlab/modules/db/query/enums/_union.py +6 -0
  126. flowlab/modules/db/query/expressions/__init__.py +22 -0
  127. flowlab/modules/db/query/expressions/_alias.py +41 -0
  128. flowlab/modules/db/query/expressions/_current_timestamp.py +19 -0
  129. flowlab/modules/db/query/expressions/_excluded.py +13 -0
  130. flowlab/modules/db/query/expressions/_expression.py +26 -0
  131. flowlab/modules/db/query/expressions/_identifier.py +22 -0
  132. flowlab/modules/db/query/expressions/_postgres_array.py +33 -0
  133. flowlab/modules/db/query/expressions/_raw.py +22 -0
  134. flowlab/modules/db/query/expressions/_sql.py +18 -0
  135. flowlab/modules/db/query/expressions/_sub_query.py +26 -0
  136. flowlab/modules/db/result/__init__.py +15 -0
  137. flowlab/modules/db/result/_base.py +50 -0
  138. flowlab/modules/db/result/_mysql.py +107 -0
  139. flowlab/modules/db/result/_postgres.py +178 -0
  140. flowlab/modules/db/result/_result.py +30 -0
  141. flowlab/modules/db/result/_sqlite.py +65 -0
  142. flowlab/modules/migrator/__init__.py +12 -0
  143. flowlab/modules/migrator/_loader.py +52 -0
  144. flowlab/modules/migrator/_migration_abc.py +20 -0
  145. flowlab/modules/migrator/_migrator.py +108 -0
  146. flowlab/modules/migrator/_schema.py +72 -0
  147. flowlab/modules/migrator/_template.py +35 -0
  148. flowlab/modules/queue/__init__.py +29 -0
  149. flowlab/modules/queue/_commands.py +100 -0
  150. flowlab/modules/queue/_job.py +134 -0
  151. flowlab/modules/queue/_queue.py +138 -0
  152. flowlab/modules/queue/_schema.py +28 -0
  153. flowlab/modules/queue/_worker.py +126 -0
  154. flowlab/modules/queue/adapters/__init__.py +17 -0
  155. flowlab/modules/queue/adapters/_base.py +70 -0
  156. flowlab/modules/queue/adapters/_database.py +164 -0
  157. flowlab/modules/queue/adapters/_redis.py +20 -0
  158. flowlab/modules/queue/adapters/_redis_like.py +164 -0
  159. flowlab/modules/queue/adapters/_sync.py +43 -0
  160. flowlab/modules/queue/adapters/_valkey.py +20 -0
  161. flowlab/modules/queue/migrations/0001_01_01_000002_create_jobs_table.py +41 -0
  162. flowlab/modules/ratelimit/__init__.py +15 -0
  163. flowlab/modules/ratelimit/_http.py +62 -0
  164. flowlab/modules/ratelimit/_limiter.py +69 -0
  165. flowlab/modules/ratelimit/_limits.py +44 -0
  166. flowlab/modules/ratelimit/_mcp.py +64 -0
  167. flowlab/py.typed +0 -0
  168. flowlab-0.1.0.dist-info/METADATA +233 -0
  169. flowlab-0.1.0.dist-info/RECORD +173 -0
  170. flowlab-0.1.0.dist-info/WHEEL +5 -0
  171. flowlab-0.1.0.dist-info/entry_points.txt +2 -0
  172. flowlab-0.1.0.dist-info/licenses/LICENSE +21 -0
  173. flowlab-0.1.0.dist-info/top_level.txt +1 -0
flowlab/__init__.py ADDED
@@ -0,0 +1,109 @@
1
+ from importlib.metadata import PackageNotFoundError, version
2
+
3
+ from fastapi import (
4
+ APIRouter,
5
+ BackgroundTasks,
6
+ Body,
7
+ Cookie,
8
+ Depends,
9
+ File,
10
+ Form,
11
+ Header,
12
+ HTTPException,
13
+ Path,
14
+ Query,
15
+ Request,
16
+ Response,
17
+ Security,
18
+ UploadFile,
19
+ WebSocket,
20
+ WebSocketDisconnect,
21
+ status,
22
+ )
23
+ from fastmcp.dependencies import Depends as MCPDepends
24
+
25
+ from flowlab._cache import Cache, get_cache
26
+ from flowlab._database import DB, INTEGRITY_ERRORS, get_db
27
+ from flowlab._exceptions import (
28
+ AuthNotEnabled,
29
+ FlowLabAlreadyInitialized,
30
+ FlowLabError,
31
+ FlowLabNotInitialized,
32
+ NotConnected,
33
+ SchemaMismatch,
34
+ )
35
+ from flowlab._flowlab import FlowLab
36
+ from flowlab._module import Module
37
+ from flowlab._queue import get_queue
38
+ from flowlab._routing import Command, CommandRouter, MCPRouter
39
+ from flowlab._settings import (
40
+ AppEnv,
41
+ AuthSettings,
42
+ CacheDriver,
43
+ CacheSettings,
44
+ DatabaseSettings,
45
+ DBDriver,
46
+ FastAPISettings,
47
+ FastMCPSettings,
48
+ QueueDriver,
49
+ QueueSettings,
50
+ TyperSettings,
51
+ )
52
+ from flowlab._state import get_app
53
+
54
+ try:
55
+ __version__ = version("flowlab")
56
+ except PackageNotFoundError: # pragma: no cover - running from a source tree without metadata
57
+ __version__ = "0.0.0"
58
+
59
+ __all__ = [
60
+ "DB",
61
+ "INTEGRITY_ERRORS",
62
+ "APIRouter",
63
+ "AppEnv",
64
+ "AuthNotEnabled",
65
+ "AuthSettings",
66
+ "BackgroundTasks",
67
+ "Body",
68
+ "Cache",
69
+ "CacheDriver",
70
+ "CacheSettings",
71
+ "Command",
72
+ "CommandRouter",
73
+ "Cookie",
74
+ "DBDriver",
75
+ "DatabaseSettings",
76
+ "Depends",
77
+ "FastAPISettings",
78
+ "FastMCPSettings",
79
+ "File",
80
+ "FlowLab",
81
+ "FlowLabAlreadyInitialized",
82
+ "FlowLabError",
83
+ "FlowLabNotInitialized",
84
+ "Form",
85
+ "HTTPException",
86
+ "Header",
87
+ "MCPDepends",
88
+ "MCPRouter",
89
+ "Module",
90
+ "NotConnected",
91
+ "Path",
92
+ "Query",
93
+ "QueueDriver",
94
+ "QueueSettings",
95
+ "Request",
96
+ "Response",
97
+ "SchemaMismatch",
98
+ "Security",
99
+ "TyperSettings",
100
+ "UploadFile",
101
+ "WebSocket",
102
+ "WebSocketDisconnect",
103
+ "__version__",
104
+ "get_app",
105
+ "get_cache",
106
+ "get_db",
107
+ "get_queue",
108
+ "status",
109
+ ]
flowlab/__main__.py ADDED
@@ -0,0 +1,3 @@
1
+ from flowlab._console import main
2
+
3
+ main()
flowlab/_cache.py ADDED
@@ -0,0 +1,42 @@
1
+ from collections.abc import Generator
2
+ from typing import Annotated
3
+
4
+ from fastapi import Depends
5
+
6
+ from flowlab._settings import CacheDriver, CacheSettings
7
+ from flowlab._state import get_app
8
+ from flowlab.modules.cache import Cache as CacheStore
9
+ from flowlab.modules.db.database import DB as Database
10
+
11
+
12
+ def connect_cache_store(settings: CacheSettings, db: Database) -> CacheStore:
13
+ driver = settings.cache_driver
14
+ options = settings.cache_options()
15
+
16
+ if driver is CacheDriver.MEMORY:
17
+ return CacheStore.shared_memory()
18
+
19
+ if driver is CacheDriver.DATABASE:
20
+ return CacheStore.connect_database(db, **options)
21
+
22
+ if driver is CacheDriver.REDIS:
23
+ return CacheStore.connect_redis(**options)
24
+
25
+ if driver is CacheDriver.VALKEY:
26
+ return CacheStore.connect_valkey(**options)
27
+
28
+ if driver is CacheDriver.MEMCACHED:
29
+ return CacheStore.connect_memcached(**options)
30
+
31
+ raise ValueError(f"Unsupported CACHE_DRIVER: {driver!r}")
32
+
33
+
34
+ def get_cache() -> CacheStore:
35
+ return get_app().cache
36
+
37
+
38
+ def connect_cache() -> Generator[CacheStore, None, None]:
39
+ yield get_cache()
40
+
41
+
42
+ Cache = Annotated[CacheStore, Depends(connect_cache)]
flowlab/_commands.py ADDED
@@ -0,0 +1,101 @@
1
+ import os
2
+ import subprocess
3
+ import sys
4
+ from typing import Annotated
5
+
6
+ import typer
7
+ import uvicorn
8
+
9
+ from flowlab._routing import CommandRouter
10
+ from flowlab._state import get_app
11
+ from flowlab.modules.migrator import drop_all_tables
12
+ from flowlab.modules.migrator._schema import scaffold
13
+
14
+ RELOAD_TARGET_ENV = "FLOWLAB_RELOAD_TARGET"
15
+
16
+ commands = CommandRouter()
17
+
18
+
19
+ @commands.command("server:start", lifespan=False)
20
+ def server_start(
21
+ host: Annotated[str | None, typer.Option(help="Interface to bind. Defaults to SERVER_HOST.")] = None,
22
+ port: Annotated[int | None, typer.Option(help="Port to bind. Defaults to SERVER_PORT.")] = None,
23
+ reload: Annotated[
24
+ bool | None, typer.Option(help="Restart on code changes. Defaults to on when APP_ENV=local.")
25
+ ] = None,
26
+ ) -> None:
27
+ app = get_app()
28
+ settings = app.fastapi_settings
29
+ host = settings.server_host if host is None else host
30
+ port = settings.server_port if port is None else port
31
+ reload = settings.is_local if reload is None else reload
32
+
33
+ if not reload:
34
+ uvicorn.run(app, host=host, port=port)
35
+ return
36
+
37
+ os.environ[RELOAD_TARGET_ENV] = app._import_string()
38
+
39
+ uvicorn.run(
40
+ "flowlab._console:reload_target",
41
+ factory=True,
42
+ host=host,
43
+ port=port,
44
+ reload=True,
45
+ app_dir=str(app.project_dir),
46
+ reload_dirs=[str(app.project_dir)],
47
+ )
48
+
49
+
50
+ @commands.command("migrations:init")
51
+ def migrations_init() -> None:
52
+ _ = get_app().migrator
53
+ typer.echo("Migrations table is ready.")
54
+
55
+
56
+ @commands.command("migrations:up")
57
+ def migrations_up() -> None:
58
+ get_app().migrator.up()
59
+ typer.echo("Migrated.")
60
+
61
+
62
+ @commands.command("migrations:down")
63
+ def migrations_down() -> None:
64
+ get_app().migrator.down()
65
+ typer.echo("Rolled back the last batch.")
66
+
67
+
68
+ @commands.command("migrations:fresh")
69
+ def migrations_fresh(
70
+ force: Annotated[bool, typer.Option("--force", help="Required when APP_ENV is production.")] = False,
71
+ ) -> None:
72
+ app = get_app()
73
+
74
+ if app.fastapi_settings.is_production and not force:
75
+ typer.echo("Refusing to drop every table in production without --force.", err=True)
76
+ raise typer.Exit(1)
77
+
78
+ for table in drop_all_tables(app.db):
79
+ typer.echo(f"Dropped {table}")
80
+
81
+ app.migrator.up()
82
+ typer.echo("Migrated.")
83
+
84
+
85
+ @commands.command("migrations:make")
86
+ def migrations_make(
87
+ name: Annotated[str, typer.Argument(help="snake_case description, e.g. create_posts_table")],
88
+ ) -> None:
89
+ app = get_app()
90
+ typer.echo(scaffold(app.db, app.migrations_dir, name))
91
+
92
+
93
+ @commands.command(
94
+ "test",
95
+ lifespan=False,
96
+ context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
97
+ )
98
+ def run_tests(ctx: typer.Context) -> None:
99
+ result = subprocess.run([sys.executable, "-m", "pytest", *ctx.args], cwd=get_app().project_dir, check=False)
100
+
101
+ raise typer.Exit(result.returncode)
flowlab/_console.py ADDED
@@ -0,0 +1,37 @@
1
+ import importlib
2
+ import os
3
+ import sys
4
+
5
+ from flowlab._commands import RELOAD_TARGET_ENV
6
+ from flowlab._flowlab import FlowLab
7
+
8
+ DEFAULT_APP = "main:app"
9
+
10
+
11
+ def load_app(target: str) -> FlowLab:
12
+ module_name, _, attribute = target.partition(":")
13
+ sys.path.insert(0, os.getcwd())
14
+
15
+ app = getattr(importlib.import_module(module_name), attribute or "app")
16
+
17
+ if not isinstance(app, FlowLab):
18
+ raise SystemExit(f"{target} is not a FlowLab application")
19
+
20
+ return app
21
+
22
+
23
+ def reload_target() -> FlowLab:
24
+ if FlowLab.initialized():
25
+ return FlowLab.instance()
26
+
27
+ return load_app(os.environ[RELOAD_TARGET_ENV])
28
+
29
+
30
+ def main() -> None:
31
+ args = sys.argv[1:]
32
+ target = os.environ.get("FLOWLAB_APP", DEFAULT_APP)
33
+
34
+ if len(args) >= 2 and args[0] == "--app":
35
+ target, args = args[1], args[2:]
36
+
37
+ load_app(target).run(args)
flowlab/_database.py ADDED
@@ -0,0 +1,64 @@
1
+ import contextlib
2
+ import importlib
3
+ import sqlite3
4
+ from collections.abc import Generator
5
+ from pathlib import Path
6
+ from typing import Annotated
7
+
8
+ from fastapi import Depends
9
+
10
+ from flowlab._settings import DatabaseSettings, DBDriver
11
+ from flowlab._state import get_app
12
+ from flowlab.modules.db.database import DB as Database
13
+
14
+ DB_API_DRIVER_MODULES = ("psycopg", "mysql.connector")
15
+
16
+ ASYNCPG_INTEGRITY_ERROR = ("asyncpg.exceptions", "IntegrityConstraintViolationError")
17
+
18
+
19
+ def _integrity_errors() -> tuple[type[BaseException], ...]:
20
+ errors: list[type[BaseException]] = [sqlite3.IntegrityError]
21
+
22
+ for module_name in DB_API_DRIVER_MODULES:
23
+ with contextlib.suppress(ImportError):
24
+ errors.append(importlib.import_module(module_name).IntegrityError)
25
+
26
+ module_name, attribute = ASYNCPG_INTEGRITY_ERROR
27
+
28
+ with contextlib.suppress(ImportError, AttributeError):
29
+ errors.append(getattr(importlib.import_module(module_name), attribute))
30
+
31
+ return tuple(errors)
32
+
33
+
34
+ INTEGRITY_ERRORS = _integrity_errors()
35
+
36
+
37
+ def connect_database(settings: DatabaseSettings, project_dir: Path) -> Database:
38
+ driver = settings.db_driver
39
+ options = settings.db_options(project_dir)
40
+
41
+ if driver is DBDriver.SQLITE:
42
+ return Database.connect_sqlite(**options)
43
+
44
+ if driver is DBDriver.POSTGRESQL:
45
+ return Database.connect_postgresql(**options)
46
+
47
+ if driver is DBDriver.MYSQL:
48
+ return Database.connect_mysql(**options)
49
+
50
+ if driver is DBDriver.MARIADB:
51
+ return Database.connect_mariadb(**options)
52
+
53
+ raise ValueError(f"Unsupported DB_DRIVER: {driver!r}")
54
+
55
+
56
+ def get_db() -> Database:
57
+ return get_app().db
58
+
59
+
60
+ def connect() -> Generator[Database, None, None]:
61
+ yield get_db()
62
+
63
+
64
+ DB = Annotated[Database, Depends(connect)]
flowlab/_exceptions.py ADDED
@@ -0,0 +1,31 @@
1
+ class FlowLabError(RuntimeError):
2
+ pass
3
+
4
+
5
+ class FlowLabNotInitialized(FlowLabError):
6
+ def __init__(self) -> None:
7
+ super().__init__("No FlowLab application has been initialized; create one with FlowLab(...) first")
8
+
9
+
10
+ class FlowLabAlreadyInitialized(FlowLabError):
11
+ def __init__(self) -> None:
12
+ super().__init__("A FlowLab application already exists; use FlowLab.instance() to reach it")
13
+
14
+
15
+ class NotConnected(FlowLabError):
16
+ def __init__(self, resource: str) -> None:
17
+ super().__init__(f"The {resource} is not connected; use it inside app.lifespan() or a running app")
18
+
19
+
20
+ class AuthNotEnabled(FlowLabError):
21
+ def __init__(self) -> None:
22
+ super().__init__("Auth is not enabled; pass auth_settings=AuthSettings() to FlowLab(...)")
23
+
24
+
25
+ class SchemaMismatch(FlowLabError):
26
+ def __init__(self, module: str, missing: list[str]) -> None:
27
+ self.missing = missing
28
+ super().__init__(
29
+ f"The {module} module needs {', '.join(missing)}. "
30
+ f"Run `{module}:install` to add its migrations, then `migrations:up`"
31
+ )