skrift 0.1.0a12__tar.gz → 0.1.0a14__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.
Files changed (76) hide show
  1. {skrift-0.1.0a12 → skrift-0.1.0a14}/PKG-INFO +3 -1
  2. {skrift-0.1.0a12 → skrift-0.1.0a14}/pyproject.toml +3 -1
  3. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/asgi.py +20 -10
  4. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/config.py +11 -14
  5. skrift-0.1.0a14/skrift/lib/__init__.py +4 -0
  6. skrift-0.1.0a14/skrift/lib/markdown.py +37 -0
  7. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/page.html +1 -1
  8. skrift-0.1.0a12/skrift/lib/__init__.py +0 -3
  9. {skrift-0.1.0a12 → skrift-0.1.0a14}/.gitignore +0 -0
  10. {skrift-0.1.0a12 → skrift-0.1.0a14}/README.md +0 -0
  11. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/__init__.py +0 -0
  12. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/__main__.py +0 -0
  13. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/admin/__init__.py +0 -0
  14. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/admin/controller.py +0 -0
  15. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/admin/navigation.py +0 -0
  16. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/env.py +0 -0
  17. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/script.py.mako +0 -0
  18. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/versions/20260120_210154_09b0364dbb7b_initial_schema.py +0 -0
  19. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/versions/20260122_152744_0b7c927d2591_add_roles_and_permissions.py +0 -0
  20. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/versions/20260122_172836_cdf734a5b847_add_sa_orm_sentinel_column.py +0 -0
  21. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/versions/20260122_175637_a9c55348eae7_remove_page_type_column.py +0 -0
  22. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/versions/20260122_200000_add_settings_table.py +0 -0
  23. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/versions/20260129_add_oauth_accounts.py +0 -0
  24. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic/versions/20260129_add_provider_metadata.py +0 -0
  25. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/alembic.ini +0 -0
  26. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/auth/__init__.py +0 -0
  27. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/auth/guards.py +0 -0
  28. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/auth/roles.py +0 -0
  29. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/auth/services.py +0 -0
  30. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/cli.py +0 -0
  31. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/controllers/__init__.py +0 -0
  32. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/controllers/auth.py +0 -0
  33. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/controllers/web.py +0 -0
  34. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/__init__.py +0 -0
  35. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/base.py +0 -0
  36. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/models/__init__.py +0 -0
  37. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/models/oauth_account.py +0 -0
  38. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/models/page.py +0 -0
  39. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/models/role.py +0 -0
  40. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/models/setting.py +0 -0
  41. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/models/user.py +0 -0
  42. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/services/__init__.py +0 -0
  43. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/services/oauth_service.py +0 -0
  44. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/services/page_service.py +0 -0
  45. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/db/services/setting_service.py +0 -0
  46. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/lib/exceptions.py +0 -0
  47. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/lib/template.py +0 -0
  48. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/setup/__init__.py +0 -0
  49. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/setup/config_writer.py +0 -0
  50. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/setup/controller.py +0 -0
  51. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/setup/middleware.py +0 -0
  52. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/setup/providers.py +0 -0
  53. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/setup/state.py +0 -0
  54. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/static/css/style.css +0 -0
  55. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/admin/admin.html +0 -0
  56. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/admin/base.html +0 -0
  57. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/admin/pages/edit.html +0 -0
  58. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/admin/pages/list.html +0 -0
  59. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/admin/settings/site.html +0 -0
  60. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/admin/users/list.html +0 -0
  61. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/admin/users/roles.html +0 -0
  62. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/auth/dummy_login.html +0 -0
  63. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/auth/login.html +0 -0
  64. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/base.html +0 -0
  65. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/error-404.html +0 -0
  66. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/error-500.html +0 -0
  67. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/error.html +0 -0
  68. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/index.html +0 -0
  69. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/setup/admin.html +0 -0
  70. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/setup/auth.html +0 -0
  71. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/setup/base.html +0 -0
  72. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/setup/complete.html +0 -0
  73. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/setup/configuring.html +0 -0
  74. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/setup/database.html +0 -0
  75. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/setup/restart.html +0 -0
  76. {skrift-0.1.0a12 → skrift-0.1.0a14}/skrift/templates/setup/site.html +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skrift
3
- Version: 0.1.0a12
3
+ Version: 0.1.0a14
4
4
  Summary: A lightweight async Python CMS for crafting modern websites
5
5
  Requires-Python: >=3.13
6
6
  Requires-Dist: advanced-alchemy>=0.26.0
@@ -9,6 +9,8 @@ Requires-Dist: alembic>=1.14.0
9
9
  Requires-Dist: asyncpg>=0.30.0
10
10
  Requires-Dist: httpx>=0.28.0
11
11
  Requires-Dist: litestar[cryptography,jinja,standard]>=2.14.0
12
+ Requires-Dist: markdown-it-py>=3.0.0
13
+ Requires-Dist: mdit-py-plugins>=0.4.0
12
14
  Requires-Dist: pydantic-settings>=2.7.0
13
15
  Requires-Dist: python-dotenv>=1.0.0
14
16
  Requires-Dist: pyyaml>=6.0.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "skrift"
3
- version = "0.1.0a12"
3
+ version = "0.1.0a14"
4
4
  description = "A lightweight async Python CMS for crafting modern websites"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -17,6 +17,8 @@ dependencies = [
17
17
  "uvicorn>=0.34.0",
18
18
  "pyyaml>=6.0.0",
19
19
  "ruamel.yaml>=0.18.0",
20
+ "markdown-it-py>=3.0.0",
21
+ "mdit-py-plugins>=0.4.0",
20
22
  ]
21
23
 
22
24
  [project.scripts]
@@ -44,6 +44,7 @@ from skrift.db.services.setting_service import (
44
44
  SETUP_COMPLETED_AT_KEY,
45
45
  )
46
46
  from skrift.lib.exceptions import http_exception_handler, internal_server_error_handler
47
+ from skrift.lib.markdown import render_markdown
47
48
 
48
49
 
49
50
  def load_controllers() -> list:
@@ -423,16 +424,20 @@ def create_app() -> Litestar:
423
424
  # Search working directory first for user overrides, then package directory
424
425
  working_dir_templates = Path(os.getcwd()) / "templates"
425
426
  template_dir = Path(__file__).parent / "templates"
426
- template_config = TemplateConfig(
427
- directory=[working_dir_templates, template_dir],
428
- engine=JinjaTemplateEngine,
429
- engine_callback=lambda engine: engine.engine.globals.update({
427
+ def configure_template_engine(engine):
428
+ engine.engine.globals.update({
430
429
  "now": datetime.now,
431
430
  "site_name": get_cached_site_name,
432
431
  "site_tagline": get_cached_site_tagline,
433
432
  "site_copyright_holder": get_cached_site_copyright_holder,
434
433
  "site_copyright_start_year": get_cached_site_copyright_start_year,
435
- }),
434
+ })
435
+ engine.engine.filters.update({"markdown": render_markdown})
436
+
437
+ template_config = TemplateConfig(
438
+ directory=[working_dir_templates, template_dir],
439
+ engine=JinjaTemplateEngine,
440
+ engine_callback=configure_template_engine,
436
441
  )
437
442
 
438
443
  # Static files - working directory first for user overrides, then package directory
@@ -498,16 +503,21 @@ def create_setup_app() -> Litestar:
498
503
  # Search working directory first for user overrides, then package directory
499
504
  working_dir_templates = Path(os.getcwd()) / "templates"
500
505
  template_dir = Path(__file__).parent / "templates"
501
- template_config = TemplateConfig(
502
- directory=[working_dir_templates, template_dir],
503
- engine=JinjaTemplateEngine,
504
- engine_callback=lambda engine: engine.engine.globals.update({
506
+
507
+ def configure_setup_template_engine(engine):
508
+ engine.engine.globals.update({
505
509
  "now": datetime.now,
506
510
  "site_name": lambda: "Skrift",
507
511
  "site_tagline": lambda: "Setup",
508
512
  "site_copyright_holder": lambda: "",
509
513
  "site_copyright_start_year": lambda: None,
510
- }),
514
+ })
515
+ engine.engine.filters.update({"markdown": render_markdown})
516
+
517
+ template_config = TemplateConfig(
518
+ directory=[working_dir_templates, template_dir],
519
+ engine=JinjaTemplateEngine,
520
+ engine_callback=configure_setup_template_engine,
511
521
  )
512
522
 
513
523
  # Static files - working directory first for user overrides, then package directory
@@ -229,31 +229,28 @@ def is_config_valid() -> tuple[bool, str | None]:
229
229
  @lru_cache
230
230
  def get_settings() -> Settings:
231
231
  """Load settings from .env and app.yaml."""
232
- # First create base settings from .env
233
- base_settings = Settings()
234
-
235
232
  # Load app.yaml config
236
233
  try:
237
234
  app_config = load_app_config()
238
235
  except FileNotFoundError:
239
- return base_settings
236
+ return Settings()
240
237
  except ValueError:
241
238
  # Missing environment variables - return base settings
242
- return base_settings
239
+ return Settings()
243
240
 
244
- # Merge YAML config with settings
245
- updates = {}
241
+ # Build nested configs from YAML - pass directly to Settings to avoid
242
+ # model_copy issues with nested BaseModel instances in Pydantic v2
243
+ kwargs = {}
246
244
 
247
245
  if "db" in app_config:
248
- updates["db"] = DatabaseConfig(**app_config["db"])
246
+ kwargs["db"] = DatabaseConfig(**app_config["db"])
249
247
 
250
248
  if "auth" in app_config:
251
- updates["auth"] = AuthConfig(**app_config["auth"])
249
+ kwargs["auth"] = AuthConfig(**app_config["auth"])
252
250
 
253
251
  if "session" in app_config:
254
- updates["session"] = SessionConfig(**app_config["session"])
255
-
256
- if updates:
257
- return base_settings.model_copy(update=updates)
252
+ kwargs["session"] = SessionConfig(**app_config["session"])
258
253
 
259
- return base_settings
254
+ # Create Settings with YAML nested configs
255
+ # BaseSettings will still load debug/secret_key from env, but kwargs take precedence
256
+ return Settings(**kwargs)
@@ -0,0 +1,4 @@
1
+ from skrift.lib.markdown import render_markdown
2
+ from skrift.lib.template import Template
3
+
4
+ __all__ = ["Template", "render_markdown"]
@@ -0,0 +1,37 @@
1
+ """Markdown rendering utilities for page content."""
2
+
3
+ from markdown_it import MarkdownIt
4
+ from mdit_py_plugins.footnote import footnote_plugin
5
+
6
+
7
+ def create_markdown_renderer() -> MarkdownIt:
8
+ """Create a configured markdown renderer with standard plugins."""
9
+ md = MarkdownIt("commonmark", {"typographer": True})
10
+ md.enable("table")
11
+ footnote_plugin(md)
12
+ return md
13
+
14
+
15
+ _renderer: MarkdownIt | None = None
16
+
17
+
18
+ def get_renderer() -> MarkdownIt:
19
+ """Get the singleton markdown renderer, creating it if needed."""
20
+ global _renderer
21
+ if _renderer is None:
22
+ _renderer = create_markdown_renderer()
23
+ return _renderer
24
+
25
+
26
+ def render_markdown(content: str) -> str:
27
+ """Render markdown content to HTML.
28
+
29
+ Args:
30
+ content: Markdown text to render.
31
+
32
+ Returns:
33
+ Rendered HTML string. Returns empty string for empty/None input.
34
+ """
35
+ if not content:
36
+ return ""
37
+ return get_renderer().render(content)
@@ -14,7 +14,7 @@
14
14
  </header>
15
15
 
16
16
  <div class="page-content">
17
- {{ page.content | safe }}
17
+ {{ page.content | markdown | safe }}
18
18
  </div>
19
19
 
20
20
  {% if not page.is_published %}
@@ -1,3 +0,0 @@
1
- from skrift.lib.template import Template
2
-
3
- __all__ = ["Template"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes