vibetuner 2.18.1__py3-none-any.whl → 2.26.9__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.

Potentially problematic release.


This version of vibetuner might be problematic. Click here for more details.

vibetuner/cli/__init__.py CHANGED
@@ -1,16 +1,20 @@
1
1
  # ABOUTME: Core CLI setup with AsyncTyper wrapper and base configuration
2
2
  # ABOUTME: Provides main CLI entry point and logging configuration
3
+ import importlib.metadata
3
4
  import inspect
4
5
  from functools import partial, wraps
5
6
  from importlib import import_module
7
+ from pathlib import Path
8
+ from typing import Annotated
6
9
 
7
10
  import asyncer
8
11
  import typer
9
12
  from rich.console import Console
13
+ from rich.table import Table
10
14
 
11
15
  from vibetuner.cli.run import run_app
12
16
  from vibetuner.cli.scaffold import scaffold_app
13
- from vibetuner.logging import LogLevel, setup_logging
17
+ from vibetuner.logging import LogLevel, logger, setup_logging
14
18
 
15
19
 
16
20
  console = Console()
@@ -69,11 +73,69 @@ def callback(log_level: LogLevel | None = LOG_LEVEL_OPTION) -> None:
69
73
  setup_logging(level=log_level)
70
74
 
71
75
 
76
+ @app.command()
77
+ def version(
78
+ show_app: bool = typer.Option(
79
+ False,
80
+ "--app",
81
+ "-a",
82
+ help="Show app settings version even if not in a project directory",
83
+ ),
84
+ ) -> None:
85
+ """Show version information."""
86
+ try:
87
+ # Get vibetuner package version
88
+ vibetuner_version = importlib.metadata.version("vibetuner")
89
+ except importlib.metadata.PackageNotFoundError:
90
+ vibetuner_version = "unknown"
91
+
92
+ # Create table for nice display
93
+ table = Table(title="Version Information")
94
+ table.add_column("Component", style="cyan", no_wrap=True)
95
+ table.add_column("Version", style="green", no_wrap=True)
96
+
97
+ # Always show vibetuner package version
98
+ table.add_row("vibetuner package", vibetuner_version)
99
+
100
+ # Show app version if requested or if in a project
101
+ try:
102
+ from vibetuner.config import CoreConfiguration
103
+
104
+ settings = CoreConfiguration()
105
+ table.add_row(f"{settings.project.project_name} settings", settings.version)
106
+ except Exception:
107
+ if show_app:
108
+ table.add_row("app settings", "not in project directory")
109
+ # else: don't show app version if not in project and not requested
110
+
111
+ console.print(table)
112
+
113
+
114
+ @app.command()
115
+ def core_template_symlink(
116
+ target: Annotated[
117
+ Path,
118
+ typer.Argument(
119
+ help="Path where the 'core' symlink should be created or updated",
120
+ ),
121
+ ],
122
+ ) -> None:
123
+ """Create or update a 'core' symlink to the package templates directory."""
124
+ from vibetuner.paths import create_core_templates_symlink
125
+
126
+ create_core_templates_symlink(target)
127
+
128
+
72
129
  app.add_typer(run_app, name="run")
73
130
  app.add_typer(scaffold_app, name="scaffold")
74
131
 
75
132
  try:
76
133
  import_module("app.cli")
77
- except (ImportError, ModuleNotFoundError):
134
+ except ModuleNotFoundError:
135
+ # Silent pass for missing app.cli module (expected in some projects)
78
136
  pass
79
- # Cache buster
137
+ except ImportError as e:
138
+ # Log warning for any import error (including syntax errors, missing dependencies, etc.)
139
+ logger.warning(
140
+ f"Failed to import app.cli: {e}. User CLI commands will not be available."
141
+ )
vibetuner/cli/run.py CHANGED
@@ -47,7 +47,7 @@ def dev(
47
47
 
48
48
  # Call streaq programmatically
49
49
  streaq_main(
50
- worker_path="app.tasks.worker.worker",
50
+ worker_path="vibetuner.tasks.worker.worker",
51
51
  workers=1,
52
52
  reload=True,
53
53
  verbose=True,
@@ -123,7 +123,7 @@ def prod(
123
123
 
124
124
  # Call streaq programmatically
125
125
  streaq_main(
126
- worker_path="app.tasks.worker.worker",
126
+ worker_path="vibetuner.tasks.worker.worker",
127
127
  workers=workers_count,
128
128
  reload=False,
129
129
  verbose=False,
vibetuner/config.py CHANGED
@@ -141,4 +141,3 @@ settings = CoreConfiguration()
141
141
 
142
142
 
143
143
  logger.info("Configuration loaded for project: {}", settings.project.project_name)
144
- logger.info("Configuration loaded for project: {}", settings.model_dump())
@@ -4,10 +4,12 @@ from fastapi import APIRouter, Depends as Depends, FastAPI, Request
4
4
  from fastapi.responses import HTMLResponse, RedirectResponse
5
5
  from fastapi.staticfiles import StaticFiles
6
6
 
7
+ import vibetuner.frontend.lifespan as lifespan_module
7
8
  from vibetuner import paths
9
+ from vibetuner.logging import logger
8
10
 
9
11
  from .deps import LangDep as LangDep, MagicCookieDep as MagicCookieDep
10
- from .lifespan import ctx, lifespan
12
+ from .lifespan import ctx
11
13
  from .middleware import middlewares
12
14
  from .routes import auth, debug, health, language, meta, user
13
15
  from .templates import render_template
@@ -21,15 +23,35 @@ def register_router(router: APIRouter) -> None:
21
23
 
22
24
 
23
25
  try:
24
- import app.frontend.oauth as _app_oauth # noqa: F401 # type: ignore[unresolved-import]
25
- import app.frontend.routes as _app_routes # noqa: F401 # type: ignore[unresolved-import]
26
+ import app.frontend.oauth as _app_oauth # type: ignore[unresolved-import] # noqa: F401
27
+ import app.frontend.routes as _app_routes # type: ignore[unresolved-import] # noqa: F401
26
28
 
27
29
  # Register OAuth routes after providers are registered
28
30
  from .routes.auth import register_oauth_routes
29
31
 
30
32
  register_oauth_routes()
31
- except (ImportError, ModuleNotFoundError):
33
+ except ModuleNotFoundError:
34
+ # Silent pass for missing app.frontend.oauth or app.frontend.routes modules (expected in some projects)
32
35
  pass
36
+ except ImportError as e:
37
+ # Log warning for any import error (including syntax errors, missing dependencies, etc.)
38
+ logger.warning(
39
+ f"Failed to import app.frontend.oauth or app.frontend.routes: {e}. OAuth and custom routes will not be available."
40
+ )
41
+
42
+ try:
43
+ from app.frontend.middleware import (
44
+ middlewares as app_middlewares, # type: ignore[unresolved-import]
45
+ )
46
+
47
+ middlewares.extend(app_middlewares)
48
+ except ModuleNotFoundError:
49
+ pass
50
+ except ImportError as e:
51
+ # Log warning for any import error (including syntax errors, missing dependencies, etc.)
52
+ logger.warning(
53
+ f"Failed to import app.frontend.middleware: {e}. Additional middlewares will not be available."
54
+ )
33
55
 
34
56
 
35
57
  dependencies: list[Any] = [
@@ -38,7 +60,7 @@ dependencies: list[Any] = [
38
60
 
39
61
  app = FastAPI(
40
62
  debug=ctx.DEBUG,
41
- lifespan=lifespan,
63
+ lifespan=lifespan_module.lifespan,
42
64
  docs_url=None,
43
65
  redoc_url=None,
44
66
  openapi_url=None,
@@ -1,4 +1,5 @@
1
1
  from contextlib import asynccontextmanager
2
+ from typing import AsyncGenerator
2
3
 
3
4
  from fastapi import FastAPI
4
5
 
@@ -10,7 +11,7 @@ from .hotreload import hotreload
10
11
 
11
12
 
12
13
  @asynccontextmanager
13
- async def base_lifespan(app: FastAPI):
14
+ async def base_lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
14
15
  logger.info("Vibetuner frontend starting")
15
16
  if ctx.DEBUG:
16
17
  await hotreload.startup()
@@ -27,5 +28,10 @@ async def base_lifespan(app: FastAPI):
27
28
 
28
29
  try:
29
30
  from app.frontend.lifespan import lifespan # ty: ignore
30
- except ImportError:
31
+ except ModuleNotFoundError:
32
+ # Silent pass for missing app.frontend.lifespan module (expected in some projects)
33
+ lifespan = base_lifespan
34
+ except ImportError as e:
35
+ # Log warning for any import error (including syntax errors, missing dependencies, etc.)
36
+ logger.warning(f"Failed to import app.frontend.lifespan: {e}. Using base lifespan.")
31
37
  lifespan = base_lifespan
@@ -126,7 +126,6 @@ class AuthBackend(AuthenticationBackend):
126
126
  return None
127
127
 
128
128
 
129
- # Until this line
130
129
  middlewares: list[Middleware] = [
131
130
  Middleware(TrustedHostMiddleware),
132
131
  Middleware(ForwardedProtocolMiddleware),
@@ -145,7 +144,4 @@ middlewares: list[Middleware] = [
145
144
  ),
146
145
  Middleware(AdjustLangCookieMiddleware),
147
146
  Middleware(AuthenticationMiddleware, backend=AuthBackend()),
148
- # Add your middleware below this line
149
147
  ]
150
-
151
- # EOF
@@ -7,7 +7,7 @@ from starlette.responses import HTMLResponse
7
7
  from starlette_babel import gettext_lazy as _, gettext_lazy as ngettext
8
8
  from starlette_babel.contrib.jinja import configure_jinja_env
9
9
 
10
- from vibetuner.context import Context
10
+ from vibetuner.context import ctx as data_ctx
11
11
  from vibetuner.paths import frontend_templates
12
12
  from vibetuner.templates import render_static_template
13
13
  from vibetuner.time import age_in_timedelta
@@ -19,8 +19,6 @@ __all__ = [
19
19
  "render_static_template",
20
20
  ]
21
21
 
22
- data_ctx = Context()
23
-
24
22
 
25
23
  def timeago(dt):
26
24
  """Converts a datetime object to a human-readable string representing the time elapsed since the given datetime.
vibetuner/mongo.py CHANGED
@@ -1,13 +1,28 @@
1
+ from importlib import import_module
2
+
1
3
  from beanie import init_beanie
2
4
  from pymongo import AsyncMongoClient
3
5
 
4
6
  from vibetuner.config import settings
7
+ from vibetuner.logging import logger
5
8
  from vibetuner.models.registry import get_all_models
6
9
 
7
10
 
8
11
  async def init_models() -> None:
9
12
  """Initialize MongoDB connection and register all Beanie models."""
10
13
 
14
+ # Try to import user models to trigger their registration
15
+ try:
16
+ import_module("app.models")
17
+ except ModuleNotFoundError:
18
+ # Silent pass for missing app.models module (expected in some projects)
19
+ pass
20
+ except ImportError as e:
21
+ # Log warning for any import error (including syntax errors, missing dependencies, etc.)
22
+ logger.warning(
23
+ f"Failed to import app.models: {e}. User models will not be registered."
24
+ )
25
+
11
26
  client: AsyncMongoClient = AsyncMongoClient(
12
27
  host=str(settings.mongodb_url),
13
28
  compressors=["zstd"],
vibetuner/paths.py CHANGED
@@ -5,6 +5,8 @@ from typing import Self
5
5
  from pydantic import computed_field, model_validator
6
6
  from pydantic_settings import BaseSettings, SettingsConfigDict
7
7
 
8
+ from vibetuner.logging import logger
9
+
8
10
 
9
11
  # Package-relative paths (for bundled templates in the vibetuner package)
10
12
  _package_files = files("vibetuner")
@@ -22,6 +24,35 @@ def _get_package_templates_path() -> Path:
22
24
  ) from None
23
25
 
24
26
 
27
+ def create_core_templates_symlink(target: Path) -> None:
28
+ """Create or update a 'core' symlink pointing to the package templates directory."""
29
+
30
+ try:
31
+ source = _get_package_templates_path().resolve()
32
+ except RuntimeError as e:
33
+ logger.error(f"Cannot create symlink: {e}")
34
+ return
35
+
36
+ # Case 1: target does not exist → create symlink
37
+ if not target.exists():
38
+ target.symlink_to(source, target_is_directory=True)
39
+ logger.info(f"Created symlink '{target}' → '{source}'")
40
+ return
41
+
42
+ # Case 2: exists but is not a symlink → error
43
+ if not target.is_symlink():
44
+ logger.error(f"Cannot create symlink: '{target}' exists and is not a symlink.")
45
+ raise FileExistsError(
46
+ f"Cannot create symlink: '{target}' exists and is not a symlink."
47
+ )
48
+
49
+ # Case 3: is a symlink but points somewhere else → update it
50
+ if target.resolve() != source:
51
+ target.unlink()
52
+ target.symlink_to(source, target_is_directory=True)
53
+ logger.info(f"Updated symlink '{target}' → '{source}'")
54
+
55
+
25
56
  # Package templates always available
26
57
  package_templates = _get_package_templates_path()
27
58
  core_templates = package_templates # Alias for backwards compatibility
@@ -158,10 +189,6 @@ class PathSettings(BaseSettings):
158
189
  paths.append(package_templates / "markdown")
159
190
  return paths
160
191
 
161
- def set_root(self, project_root: Path) -> None:
162
- """Explicitly set project root (overrides auto-detection)."""
163
- self.root = project_root
164
-
165
192
  def to_template_path_list(self, path: Path) -> list[Path]:
166
193
  """Convert path to list with fallback."""
167
194
  return [path, path / self.fallback_path]
@@ -191,12 +218,6 @@ class PathSettings(BaseSettings):
191
218
  _settings = PathSettings()
192
219
 
193
220
 
194
- # Backwards-compatible module-level API
195
- def set_project_root(project_root: Path) -> None:
196
- """Set the project root directory explicitly."""
197
- _settings.set_root(project_root)
198
-
199
-
200
221
  def to_template_path_list(path: Path) -> list[Path]:
201
222
  """Convert path to list with fallback."""
202
223
  return _settings.to_template_path_list(path)
@@ -1,2 +0,0 @@
1
- # Import all your tasks here with (noqa: F401)
2
- # from . import x_tasks
@@ -0,0 +1,28 @@
1
+ from contextlib import asynccontextmanager
2
+ from typing import AsyncGenerator
3
+
4
+ from vibetuner.context import Context, ctx
5
+ from vibetuner.logging import logger
6
+ from vibetuner.mongo import init_models
7
+
8
+
9
+ @asynccontextmanager
10
+ async def base_lifespan() -> AsyncGenerator[Context, None]:
11
+ logger.info("Vibetuner task worker starting")
12
+
13
+ await init_models()
14
+
15
+ yield ctx
16
+
17
+ logger.info("Vibetuner task worker stopping")
18
+
19
+
20
+ try:
21
+ from app.tasks.lifespan import lifespan # ty: ignore
22
+ except ModuleNotFoundError:
23
+ # Silent pass for missing app.tasks.lifespan module (expected in some projects)
24
+ lifespan = base_lifespan
25
+ except ImportError as e:
26
+ # Log warning for any import error (including syntax errors, missing dependencies, etc.)
27
+ logger.warning(f"Failed to import app.tasks.lifespan: {e}. Using base lifespan.")
28
+ lifespan = base_lifespan
vibetuner/tasks/worker.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from streaq import Worker
2
2
 
3
3
  from vibetuner.config import settings
4
- from vibetuner.tasks.context import lifespan
4
+ from vibetuner.tasks.lifespan import lifespan
5
5
 
6
6
 
7
7
  worker = Worker(
@@ -13,6 +13,3 @@ worker = Worker(
13
13
  ),
14
14
  lifespan=lifespan,
15
15
  )
16
-
17
- # Register tasks
18
- # use something like from . import task_module_name // noqa: E402, F401
vibetuner/versioning.py CHANGED
@@ -1,8 +1,12 @@
1
+ from vibetuner.logging import logger
2
+
3
+
1
4
  __version__ = "0.0.0-default"
2
5
 
3
6
  try:
4
7
  from app._version import version as __version__ # type: ignore
5
- except ImportError:
6
- pass
8
+ except (ImportError, ModuleNotFoundError) as e:
9
+ # Log warning for both ImportError and ModuleNotFoundError as requested
10
+ logger.warning(f"Failed to import app._version: {e}. Using default version.")
7
11
 
8
12
  version = __version__
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: vibetuner
3
- Version: 2.18.1
3
+ Version: 2.26.9
4
4
  Summary: Core Python framework and blessed dependencies for production-ready FastAPI + MongoDB + HTMX projects
5
5
  Keywords: fastapi,mongodb,htmx,web-framework,scaffolding,oauth,background-jobs
6
6
  Author: All Tuner Labs, S.L.
@@ -21,11 +21,11 @@ Requires-Dist: arel>=0.4.0
21
21
  Requires-Dist: asyncer>=0.0.10
22
22
  Requires-Dist: authlib>=1.6.5
23
23
  Requires-Dist: beanie[zstd]>=2.0.0
24
- Requires-Dist: click>=8.3.0
24
+ Requires-Dist: click>=8.3.1
25
25
  Requires-Dist: copier>=9.10.3,<9.10.4
26
26
  Requires-Dist: email-validator>=2.3.0
27
- Requires-Dist: fastapi[standard-no-fastapi-cloud-cli]>=0.121.1
28
- Requires-Dist: granian[pname]>=2.5.7
27
+ Requires-Dist: fastapi[standard-no-fastapi-cloud-cli]>=0.121.2
28
+ Requires-Dist: granian[pname]>=2.6.0
29
29
  Requires-Dist: httpx[http2]>=0.28.1
30
30
  Requires-Dist: itsdangerous>=2.2.0
31
31
  Requires-Dist: loguru>=0.7.3
@@ -45,12 +45,12 @@ Requires-Dist: cloudflare>=4.3.1 ; extra == 'dev'
45
45
  Requires-Dist: djlint>=1.36.4 ; extra == 'dev'
46
46
  Requires-Dist: dunamai>=1.25.0 ; extra == 'dev'
47
47
  Requires-Dist: gh-bin>=2.83.0 ; extra == 'dev'
48
- Requires-Dist: granian[pname,reload]>=2.5.7 ; extra == 'dev'
48
+ Requires-Dist: granian[pname,reload]>=2.6.0 ; extra == 'dev'
49
49
  Requires-Dist: just-bin>=1.43.0 ; extra == 'dev'
50
50
  Requires-Dist: pre-commit>=4.4.0 ; extra == 'dev'
51
51
  Requires-Dist: pysemver>=0.5.0 ; extra == 'dev'
52
- Requires-Dist: ruff>=0.14.4 ; extra == 'dev'
53
- Requires-Dist: rumdl>=0.0.174 ; extra == 'dev'
52
+ Requires-Dist: ruff>=0.14.5 ; extra == 'dev'
53
+ Requires-Dist: rumdl>=0.0.177 ; extra == 'dev'
54
54
  Requires-Dist: semver>=3.0.4 ; extra == 'dev'
55
55
  Requires-Dist: taplo>=0.9.3 ; extra == 'dev'
56
56
  Requires-Dist: ty>=0.0.1a26 ; extra == 'dev'
@@ -1,17 +1,16 @@
1
1
  vibetuner/__init__.py,sha256=rFIVCmxkKTT_g477V8biCw0lgpudyuUabXhYxg189lY,90
2
2
  vibetuner/__main__.py,sha256=Ye9oBAgXhcYQ4I4yZli3TIXF5lWQ9yY4tTPs4XnDDUY,29
3
- vibetuner/cli/__init__.py,sha256=IY2wJ_ErX2PimyYSe5SL_zGrENSWLgW-cXgMRXNC7pE,1992
4
- vibetuner/cli/run.py,sha256=mHvZypizNfVwdLo7k8SvBO7HPUF4Vka9hjJlECZCGfA,5009
3
+ vibetuner/cli/__init__.py,sha256=9FFy0MTOhWVS-Z310auNTcpbG1xJtku0TS35Qxoyt-Q,3995
4
+ vibetuner/cli/run.py,sha256=TILyvy-bZTKWcAK-K2SNYqqD-G3ypCay-ghadGztqRQ,5021
5
5
  vibetuner/cli/scaffold.py,sha256=qADWxx1gYECQ8N6dgvJmlucT6mZ29rxWu3VZhbWmhC0,5710
6
- vibetuner/config.py,sha256=Z-o7jP1dLvPR0yVzW9wPvRgQezbl6Be40EpuG9i9Eos,4157
6
+ vibetuner/config.py,sha256=oG5naa6pu8wM4hzra0xaRQCPnQWbid9hGTJOHfsmHeI,4082
7
7
  vibetuner/context.py,sha256=h4f4FfkmLlOD6WiSLhx7-IjFvIA4zcrsAp6478l6npg,743
8
- vibetuner/frontend/__init__.py,sha256=QpQY9kUWvKzMtMCh9Lcoyz1dNdYfW1d_Ue4WUnzz_No,3017
9
- vibetuner/frontend/context.py,sha256=yd9mJ8Cj9AUeHE533dofEoyCkw6oSPowdq397whfN_s,169
8
+ vibetuner/frontend/__init__.py,sha256=DIAnvQHCFNBc5VtBXYE6IdAnIqCYTD_EyFAbmui7vW8,3927
10
9
  vibetuner/frontend/deps.py,sha256=b3ocC_ryaK2Jp51SfcFqckrXiaL7V-chkFRqLjzgA_c,1296
11
10
  vibetuner/frontend/email.py,sha256=k0d7FCZCge5VYOKp3fLsbx7EA5_SrtBkpMs57o4W7u0,1119
12
11
  vibetuner/frontend/hotreload.py,sha256=Gl7FIKJaiCVVoyWQqdErBUOKDP1cGBFUpGzqHMiJd10,285
13
- vibetuner/frontend/lifespan.py,sha256=iKrRcEaPn5Q2B4ZZhMKzXE-hBM8OxjwMn6A5Q1FUbWY,679
14
- vibetuner/frontend/middleware.py,sha256=aVsEeXGuBqcBB_IlmtBW_3icuvVix7P3A63AkyeX_38,4957
12
+ vibetuner/frontend/lifespan.py,sha256=ZduSyH6E2_IW9vFWH5jww2R22mRybSm_mNfbtDHnsS0,1074
13
+ vibetuner/frontend/middleware.py,sha256=iOqcp-7WwRqHLYa1dg3xDzAXGrpqmYpqBmtQcdd9obY,4890
15
14
  vibetuner/frontend/oauth.py,sha256=EzEwoOZ_8xn_CiqAWpNoEdhV2NPxZKKwF2bA6W6Bkj0,5884
16
15
  vibetuner/frontend/routes/__init__.py,sha256=nHhiylHIUPZ2R-Bd7vXEGHLJBQ7fNuzPTJodjJR3lyc,428
17
16
  vibetuner/frontend/routes/auth.py,sha256=vKE-Dm2yPXReaOLvcxfT4a6df1dKUoteZ4p46v8Elm4,4331
@@ -20,7 +19,7 @@ vibetuner/frontend/routes/health.py,sha256=_XkMpdMNUemu7qzkGkqn5TBnZmGrArA3Xps5C
20
19
  vibetuner/frontend/routes/language.py,sha256=wHNfdewqWfK-2JLXwglu0Q0b_e00HFGd0A2-PYT44LE,1240
21
20
  vibetuner/frontend/routes/meta.py,sha256=pSyIxQsiB0QZSYwCQbS07KhkT5oHC5r9jvjUDIqZRGw,1409
22
21
  vibetuner/frontend/routes/user.py,sha256=b8ow6IGnfsHosSwSmEIYZtuQJnW_tacnNjp_aMnqWxU,2666
23
- vibetuner/frontend/templates.py,sha256=1k2jCGBdMx9U9RDcHmuO6fiNEXrRYZ0Mzk51H9XAlrM,5322
22
+ vibetuner/frontend/templates.py,sha256=xHpLMyAEjKWHgbloE40n6Fe3gjTuG5msWeqqYyJO3uU,5308
24
23
  vibetuner/logging.py,sha256=9eNofqVtKZCBDS33NbBI7Sv2875gM8MNStTSCjX2AXQ,2409
25
24
  vibetuner/models/__init__.py,sha256=JvmQvzDIxaI7zlk-ROCWEbuzxXSUOqCshINUjgu-AfQ,325
26
25
  vibetuner/models/blob.py,sha256=F30HFS4Z_Bji_PGPflWIv4dOwqKLsEWQHcjW1Oz_79M,2523
@@ -30,14 +29,14 @@ vibetuner/models/oauth.py,sha256=BdOZbW47Das9ntHTtRmVdl1lB5zLCcXW2fyVJ-tQ_F8,150
30
29
  vibetuner/models/registry.py,sha256=O5YG7vOrWluqpH5N7m44v72wbscMhU_Pu3TJw_u0MTk,311
31
30
  vibetuner/models/types.py,sha256=Lj3ASEvx5eNgQMcVhNyKQHHolJqDxj2yH8S-M9oa4J8,402
32
31
  vibetuner/models/user.py,sha256=ttcSH4mVREPhA6bCFUWXKfJ9_8_Iq3lEYXe3rDrslw4,2696
33
- vibetuner/mongo.py,sha256=F8AzD33LWQ6jq7kFUqQPSPDSr7KPlbOy8THsvXHFKdg,504
34
- vibetuner/paths.py,sha256=WFHuaanFOBI7v7xOHjyLvNMYKwX0KqOyi63x62wLE-M,7470
32
+ vibetuner/mongo.py,sha256=BejYrqHrupNfvNhEu6xUakCnRQy3YdiExk2r6hkafOs,1056
33
+ vibetuner/paths.py,sha256=IEH_GCJTThUPU0HWxr86j61IcwYgwXBamoWNmaJsxlo,8252
35
34
  vibetuner/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
35
  vibetuner/services/blob.py,sha256=-lEGIWe30yR2IuTfy5bB9Sg_PX0HoYC_WMTQ3VN28gU,5660
37
36
  vibetuner/services/email.py,sha256=IavJZS5MI40LlF_cjBpPPRx_S2r1JD4GcFg3-dWkzPA,1626
38
- vibetuner/tasks/__init__.py,sha256=uETtKOA5rJ48NBx-LN4niRJDzkb6--NHAPW3jReHABI,71
39
- vibetuner/tasks/context.py,sha256=FOFUDWGNo1h8G8qlE-1Gbkh-Kd1z3WZTqSMHkvZ68v8,869
40
- vibetuner/tasks/worker.py,sha256=-PKQ2kqvMe8X5ninULh3Vrp3M-gwh-ht2kmitvkHTVg,429
37
+ vibetuner/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ vibetuner/tasks/lifespan.py,sha256=BKOI-wbMLOqEbR4NgCKI5c9OP8W1RpxOswBL3XzPTWc,861
39
+ vibetuner/tasks/worker.py,sha256=s91Pbmz--cV4ygzDuXa-kGLZFe28HSvaXfxhIWJyIhE,340
41
40
  vibetuner/templates/email/magic_link.html.jinja,sha256=DzaCnBsYoau2JQh5enPAa2FMFFTyCwdyiM3vGhBQdtA,553
42
41
  vibetuner/templates/email/magic_link.txt.jinja,sha256=dANak9ion1cpILt45V3GcI2qnL_gKFPj7PsZKYV0m5s,200
43
42
  vibetuner/templates/frontend/base/favicons.html.jinja,sha256=A7s7YXuE82tRd7ZLJs1jGEGwBRiMPrqlWd507xL1iZg,70
@@ -65,8 +64,8 @@ vibetuner/templates/frontend/user/profile.html.jinja,sha256=qXFonyeCy99JE5o3rEta
65
64
  vibetuner/templates/markdown/.placeholder,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
65
  vibetuner/templates.py,sha256=xRoMb_oyAI5x4kxfpg56UcLKkT8e9HVn-o3KFAu9ISE,5094
67
66
  vibetuner/time.py,sha256=3_DtveCCzI20ocTnAlTh2u7FByUXtINaUoQZO-_uZow,1188
68
- vibetuner/versioning.py,sha256=UAHGoNsv3QEPAJgHyt_Q8I26SW7ng2FnZlX2-0M6r6U,156
69
- vibetuner-2.18.1.dist-info/WHEEL,sha256=DpNsHFUm_gffZe1FgzmqwuqiuPC6Y-uBCzibcJcdupM,78
70
- vibetuner-2.18.1.dist-info/entry_points.txt,sha256=aKIj9YCCXizjYupx9PeWkUJePg3ncHke_LTS5rmCsfs,49
71
- vibetuner-2.18.1.dist-info/METADATA,sha256=c_aNrSkA_hSWfazWl6Nn-9O38DWtgnofBZanp8892fo,8061
72
- vibetuner-2.18.1.dist-info/RECORD,,
67
+ vibetuner/versioning.py,sha256=c7Wg-SM-oJzQqG2RE0O8gZGHzHTgvwqa4yHn3Dk5-Sk,372
68
+ vibetuner-2.26.9.dist-info/WHEEL,sha256=w4ZtLaDgMAZW2MMZZwtH8zENekoQYBCeullI-zsXJQk,78
69
+ vibetuner-2.26.9.dist-info/entry_points.txt,sha256=aKIj9YCCXizjYupx9PeWkUJePg3ncHke_LTS5rmCsfs,49
70
+ vibetuner-2.26.9.dist-info/METADATA,sha256=WTPJkk2ZcYPzpzcWRdWDAnEgXcdjOBD3EgWo_ilp0sQ,8061
71
+ vibetuner-2.26.9.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.8
2
+ Generator: uv 0.9.9
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,10 +0,0 @@
1
- from vibetuner.context import Context
2
-
3
-
4
- class AppContext(Context):
5
- # Add typed state here
6
-
7
- model_config = {"arbitrary_types_allowed": True}
8
-
9
-
10
- ctx = AppContext()
@@ -1,34 +0,0 @@
1
- from contextlib import asynccontextmanager
2
- from typing import AsyncIterator
3
-
4
- from httpx import AsyncClient
5
- from pydantic import BaseModel
6
-
7
- from vibetuner.mongo import init_models
8
-
9
-
10
- class Context(BaseModel):
11
- http_client: AsyncClient
12
- # Add the context properties for your tasks below
13
-
14
- # Until here
15
- model_config = {"arbitrary_types_allowed": True}
16
-
17
-
18
- @asynccontextmanager
19
- async def lifespan() -> AsyncIterator[Context]:
20
- await init_models()
21
- # Add below anything that should happen before startup
22
-
23
- # Until here
24
- async with (
25
- AsyncClient() as http_client,
26
- # Add any other async context managers you need here
27
- ):
28
- yield Context(
29
- http_client=http_client,
30
- # Add any other async context managers you need here
31
- )
32
-
33
- # Add below anything that should happen before shutdown
34
- # Until here