platzky 0.3.0__py3-none-any.whl → 0.3.1__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.
platzky/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
- from .platzky import Engine as Engine
2
- from .platzky import create_app_from_config as create_app_from_config
3
- from .platzky import create_engine as create_engine
1
+ from platzky.engine import Engine as Engine
2
+ from platzky.platzky import create_app_from_config as create_app_from_config
3
+ from platzky.platzky import create_engine as create_engine
platzky/admin/admin.py ADDED
@@ -0,0 +1,33 @@
1
+ from os.path import dirname
2
+
3
+ from flask import Blueprint, render_template, session
4
+
5
+
6
+ def create_admin_blueprint(login_methods, db, locale_func):
7
+ admin = Blueprint(
8
+ "admin",
9
+ __name__,
10
+ url_prefix="/admin",
11
+ template_folder=f"{dirname(__file__)}/templates",
12
+ )
13
+
14
+ @admin.route("/", methods=["GET"])
15
+ def admin_panel_home():
16
+ user = session.get("user", None)
17
+
18
+ if not user:
19
+ return render_template("login.html", login_methods=login_methods)
20
+
21
+ cms_modules = {"plugins": [plugin.get("name") for plugin in db.get_plugins_data()]}
22
+ return render_template("admin.html", user=user, cms_modules=cms_modules)
23
+
24
+ @admin.route("/module/<module_name>", methods=["GET"])
25
+ def module_settings(module_name):
26
+ user = session.get("user", None)
27
+
28
+ if not user:
29
+ return render_template("login.html", login_methods=login_methods)
30
+
31
+ return render_template("module.html", user=user, module_name=module_name)
32
+
33
+ return admin
@@ -0,0 +1,29 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block description %}
4
+ {{ _("This is the admin page. You can manage your posts here.") }}
5
+ {% endblock %}
6
+
7
+ {% block content %}
8
+
9
+ <div class="admin-contents mx-auto w-75">
10
+ <h1>{% block title %}Admin{% endblock %}</h1>
11
+ {% if user %}
12
+ <div class="alert alert-success" role="alert">You're logged in</div>
13
+ {% endif %}
14
+ </div>
15
+
16
+ {% endblock %}
17
+
18
+ {% block left_panel %}
19
+ <div id="admin-panel">
20
+ {% for cms_module_name, cms_entries in cms_modules.items() %}
21
+ <div class="cms-module mb-2">
22
+ <p>{{ cms_module_name }}</p>
23
+ {% for cms_entry in cms_entries %}
24
+ <a href="{{ url_for('admin.module', name=cms_entry) }}" class="cms-entry btn btn-primary btn-block mb-2">{{ cms_entry }}</a>
25
+ {% endfor %}
26
+ </div>
27
+ {% endfor %}
28
+ </div>
29
+ {% endblock %}
@@ -0,0 +1,21 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block description %}
4
+ {{ _("This is the login page. You can log in here.") }}
5
+
6
+ {% endblock %}
7
+
8
+ {% block content %}
9
+
10
+ <div class="login-contents mx-auto w-75">
11
+ <h1>{% block title %}Login{% endblock %}</h1>
12
+
13
+ <div class="row align-items-center">
14
+
15
+ {% for login_method in login_methods %}
16
+ {{ login_method | safe }}
17
+ {% endfor %}
18
+ </div>
19
+ </div>
20
+
21
+ {% endblock %}
@@ -0,0 +1,9 @@
1
+ {% extends "admin.html" %}
2
+
3
+ {% block content %}
4
+
5
+ <div class="module-contents mx-auto w-75">
6
+ <h1>{% block title %}{% module_name %}{% endblock %}</h1>
7
+ </div>
8
+
9
+ {% endblock %}
platzky/db/db.py CHANGED
@@ -4,7 +4,7 @@ from typing import Any, Callable
4
4
 
5
5
  from pydantic import BaseModel, Field
6
6
 
7
- from ..models import Color, MenuItem, Page, Post
7
+ from platzky.models import Color, MenuItem, Page, Post
8
8
 
9
9
 
10
10
  class DB(ABC):
@@ -47,8 +47,3 @@ class GoogleJsonDb(Json):
47
47
 
48
48
  self.module_name = "google_json_db"
49
49
  self.db_name = "GoogleJsonDb"
50
-
51
- def __save_entry(self, entry):
52
- data = get_data(self.blob)
53
- data["data"].append(entry)
54
- self.blob.upload_from_string(json.dumps(data), content_type="application/json")
platzky/db/graph_ql_db.py CHANGED
@@ -6,8 +6,8 @@ from gql.transport.aiohttp import AIOHTTPTransport
6
6
  from gql.transport.exceptions import TransportQueryError
7
7
  from pydantic import Field
8
8
 
9
- from ..models import Color, Post
10
- from .db import DB, DBConfig
9
+ from platzky.db.db import DB, DBConfig
10
+ from platzky.models import Color, Post
11
11
 
12
12
 
13
13
  def db_config_type():
@@ -29,7 +29,7 @@ def db_from_config(config: GraphQlDbConfig):
29
29
 
30
30
  def _standarize_comment(
31
31
  comment,
32
- ): # TODO add tests for checking stadarization of comments
32
+ ):
33
33
  return {
34
34
  "author": comment["author"],
35
35
  "comment": comment["comment"],
@@ -37,7 +37,7 @@ def _standarize_comment(
37
37
  }
38
38
 
39
39
 
40
- def _standarize_post(post): # TODO add tests for checking stadarization of posts
40
+ def _standarize_post(post):
41
41
  return {
42
42
  "author": post["author"]["name"],
43
43
  "slug": post["slug"],
platzky/db/json_db.py CHANGED
@@ -73,7 +73,11 @@ class Json(DB):
73
73
  return menu_items_list
74
74
 
75
75
  def get_posts_by_tag(self, tag, lang):
76
- return (post for post in self._get_site_content()["posts"] if tag in post["tags"])
76
+ return (
77
+ post
78
+ for post in self._get_site_content()["posts"]
79
+ if tag in post["tags"] and post["language"] == lang
80
+ )
77
81
 
78
82
  def _get_site_content(self):
79
83
  content = self.data.get("site_content")
platzky/engine.py ADDED
@@ -0,0 +1,62 @@
1
+ import os
2
+
3
+ from flask import Flask, request, session
4
+ from flask_babel import Babel
5
+
6
+ from platzky.config import Config
7
+
8
+
9
+ class Engine(Flask):
10
+ def __init__(self, config: Config, db, import_name):
11
+ super().__init__(import_name)
12
+ self.config.from_mapping(config.model_dump(by_alias=True))
13
+ self.db = db
14
+ self.notifiers = []
15
+ self.login_methods = []
16
+ self.dynamic_body = ""
17
+ self.dynamic_head = ""
18
+ directory = os.path.dirname(os.path.realpath(__file__))
19
+ locale_dir = os.path.join(directory, "locale")
20
+ config.translation_directories.append(locale_dir)
21
+
22
+ babel_translation_directories = ";".join(config.translation_directories)
23
+ self.babel = Babel(
24
+ self,
25
+ locale_selector=self.get_locale,
26
+ default_translation_directories=babel_translation_directories,
27
+ )
28
+
29
+ def notify(self, message: str):
30
+ for notifier in self.notifiers:
31
+ notifier(message)
32
+
33
+ def add_notifier(self, notifier):
34
+ self.notifiers.append(notifier)
35
+
36
+ # TODO login_method should be interface
37
+ def add_login_method(self, login_method):
38
+ self.login_methods.append(login_method)
39
+
40
+ def add_dynamic_body(self, body: str):
41
+ self.dynamic_body += body
42
+
43
+ def add_dynamic_head(self, body: str):
44
+ self.dynamic_head += body
45
+
46
+ def get_locale(self) -> str:
47
+ domain = request.headers.get("Host", "localhost")
48
+ domain_to_lang = self.config.get("DOMAIN_TO_LANG")
49
+
50
+ languages = self.config.get("LANGUAGES", {}).keys()
51
+ backup_lang = session.get(
52
+ "language",
53
+ request.accept_languages.best_match(languages, "en"),
54
+ )
55
+
56
+ if domain_to_lang:
57
+ lang = domain_to_lang.get(domain, backup_lang)
58
+ else:
59
+ lang = backup_lang
60
+
61
+ session["language"] = lang
62
+ return lang
platzky/platzky.py CHANGED
@@ -1,71 +1,20 @@
1
- import os
2
1
  import typing as t
3
2
  import urllib.parse
4
3
 
5
- from flask import Flask, redirect, render_template, request, session
6
- from flask_babel import Babel
4
+ from flask import redirect, render_template, request, session
7
5
  from flask_minify import Minify
8
6
 
9
- from .blog import blog
10
- from .config import (
7
+ from platzky.admin import admin
8
+ from platzky.blog import blog
9
+ from platzky.config import (
11
10
  Config,
12
11
  languages_dict,
13
12
  )
14
- from .db.db_loader import get_db
15
- from .plugin_loader import plugify
16
- from .seo import seo
17
- from .www_handler import redirect_nonwww_to_www, redirect_www_to_nonwww
18
-
19
-
20
- class Engine(Flask):
21
- def __init__(self, config: Config, db, import_name):
22
- super().__init__(import_name)
23
- self.config.from_mapping(config.model_dump(by_alias=True))
24
- self.db = db
25
- self.notifiers = []
26
- self.dynamic_body = ""
27
- self.dynamic_head = ""
28
- directory = os.path.dirname(os.path.realpath(__file__))
29
- locale_dir = os.path.join(directory, "locale")
30
- config.translation_directories.append(locale_dir)
31
-
32
- babel_translation_directories = ";".join(config.translation_directories)
33
- self.babel = Babel(
34
- self,
35
- locale_selector=self.get_locale,
36
- default_translation_directories=babel_translation_directories,
37
- )
38
-
39
- def notify(self, message: str):
40
- for notifier in self.notifiers:
41
- notifier(message)
42
-
43
- def add_notifier(self, notifier):
44
- self.notifiers.append(notifier)
45
-
46
- def add_dynamic_body(self, body: str):
47
- self.dynamic_body += body
48
-
49
- def add_dynamic_head(self, body: str):
50
- self.dynamic_head += body
51
-
52
- def get_locale(self) -> str:
53
- domain = request.headers["Host"]
54
- domain_to_lang = self.config.get("DOMAIN_TO_LANG")
55
-
56
- languages = self.config.get("LANGUAGES", {}).keys()
57
- backup_lang = session.get(
58
- "language",
59
- request.accept_languages.best_match(languages, "en"),
60
- )
61
-
62
- if domain_to_lang:
63
- lang = domain_to_lang.get(domain, backup_lang)
64
- else:
65
- lang = backup_lang
66
-
67
- session["language"] = lang
68
- return lang
13
+ from platzky.db.db_loader import get_db
14
+ from platzky.engine import Engine
15
+ from platzky.plugin.plugin_loader import plugify
16
+ from platzky.seo import seo
17
+ from platzky.www_handler import redirect_nonwww_to_www, redirect_www_to_nonwww
69
18
 
70
19
 
71
20
  def create_engine(config: Config, db) -> Engine:
@@ -133,6 +82,9 @@ def create_engine(config: Config, db) -> Engine:
133
82
 
134
83
  def create_app_from_config(config: Config) -> Engine:
135
84
  engine = create_engine_from_config(config)
85
+ admin_blueprint = admin.create_admin_blueprint(
86
+ login_methods=engine.login_methods, db=engine.db, locale_func=engine.get_locale
87
+ )
136
88
  blog_blueprint = blog.create_blog_blueprint(
137
89
  db=engine.db,
138
90
  blog_prefix=config.blog_prefix,
@@ -141,6 +93,7 @@ def create_app_from_config(config: Config) -> Engine:
141
93
  seo_blueprint = seo.create_seo_blueprint(
142
94
  db=engine.db, config=engine.config, locale_func=engine.get_locale
143
95
  )
96
+ engine.register_blueprint(admin_blueprint)
144
97
  engine.register_blueprint(blog_blueprint)
145
98
  engine.register_blueprint(seo_blueprint)
146
99
 
@@ -0,0 +1,66 @@
1
+ import logging
2
+ from abc import ABC, abstractmethod
3
+ from typing import Any, Dict, Generic, Type, TypeVar
4
+
5
+ from pydantic import BaseModel, ConfigDict
6
+
7
+ from platzky.platzky import Engine as PlatzkyEngine
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class PluginError(Exception):
13
+ """Exception raised for plugin-related errors."""
14
+
15
+ pass
16
+
17
+
18
+ class ConfigPluginError(PluginError):
19
+ """Exception raised for plugin configuration-related errors."""
20
+
21
+ pass
22
+
23
+
24
+ class PluginBaseConfig(BaseModel):
25
+ """Base Pydantic model for plugin configurations.
26
+
27
+ Plugin developers should extend this class to define their own configuration schema.
28
+ """
29
+
30
+ model_config = ConfigDict(extra="allow")
31
+
32
+
33
+ T = TypeVar("T", bound=PluginBaseConfig)
34
+
35
+
36
+ class PluginBase(Generic[T], ABC):
37
+ """Abstract base class for plugins.
38
+
39
+ Plugin developers must extend this class to implement their plugins.
40
+ """
41
+
42
+ @classmethod
43
+ def get_config_model(cls) -> Type[PluginBaseConfig]:
44
+ return PluginBaseConfig
45
+
46
+ def __init__(self, config: Dict[str, Any]):
47
+ try:
48
+ config_class = self.get_config_model()
49
+ self.config = config_class.model_validate(config)
50
+ except Exception as e:
51
+ raise ConfigPluginError(f"Invalid configuration: {e}") from e
52
+
53
+ @abstractmethod
54
+ def process(self, app: PlatzkyEngine) -> PlatzkyEngine:
55
+ """Process the plugin with the given app.
56
+
57
+ Args:
58
+ app: The Flask application instance
59
+
60
+ Returns:
61
+ Platzky Engine with processed plugins
62
+
63
+ Raises:
64
+ PluginError: If plugin processing fails
65
+ """
66
+ pass
@@ -0,0 +1,109 @@
1
+ import importlib.util
2
+ import inspect
3
+ import logging
4
+ from typing import Any, Optional, Type
5
+
6
+ import deprecation
7
+
8
+ from platzky.engine import Engine
9
+ from platzky.plugin.plugin import PluginBase, PluginError
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def find_plugin(plugin_name: str) -> Any:
15
+ """Find plugin by name and return it as module.
16
+
17
+ Args:
18
+ plugin_name: name of plugin to find
19
+
20
+ Raises:
21
+ PluginError: if plugin cannot be imported
22
+
23
+ Returns:
24
+ module of plugin
25
+ """
26
+ try:
27
+ return importlib.import_module(f"platzky_{plugin_name}")
28
+ except ImportError as e:
29
+ raise PluginError(
30
+ f"Plugin {plugin_name} not found. Ensure it's installed and follows "
31
+ f"the 'platzky_<plugin_name>' naming convention"
32
+ ) from e
33
+
34
+
35
+ def _is_class_plugin(plugin_module: Any) -> Optional[Type[PluginBase[Any]]]:
36
+ """Check if the plugin module contains a PluginBase implementation.
37
+
38
+ Args:
39
+ plugin_module: The imported plugin module
40
+
41
+ Returns:
42
+ The plugin class if found, None otherwise
43
+ """
44
+ # Look for classes in the module that inherit from PluginBase
45
+ for _, obj in inspect.getmembers(plugin_module):
46
+ if inspect.isclass(obj) and issubclass(obj, PluginBase) and obj != PluginBase:
47
+ return obj
48
+ return None
49
+
50
+
51
+ @deprecation.deprecated(
52
+ deprecated_in="0.3.1",
53
+ removed_in="0.4.0",
54
+ current_version=None, # You should replace this with the current version
55
+ details="Legacy plugin style using the entrypoint process() function is deprecated. "
56
+ "Please migrate to the PluginBase interface.",
57
+ )
58
+ def _process_legacy_plugin(plugin_module, app, plugin_config, plugin_name):
59
+ """Process a legacy plugin using the entrypoint approach."""
60
+ app = plugin_module.process(app, plugin_config)
61
+ logger.info(f"Processed legacy plugin: {plugin_name}")
62
+ return app
63
+
64
+
65
+ def plugify(app: Engine) -> Engine:
66
+ """Load plugins and run their entrypoints.
67
+
68
+ Supports both class-based plugins (PluginBase) and legacy entrypoint plugins.
69
+
70
+ Args:
71
+ app: Platzky Engine instance
72
+
73
+ Returns:
74
+ Platzky Engine with processed plugins
75
+
76
+ Raises:
77
+ PluginError: if plugin processing fails
78
+ """
79
+ plugins_data = app.db.get_plugins_data()
80
+
81
+ for plugin_data in plugins_data:
82
+ plugin_config = plugin_data["config"]
83
+ plugin_name = plugin_data["name"]
84
+
85
+ try:
86
+ plugin_module = find_plugin(plugin_name)
87
+
88
+ # Check if this is a class-based plugin
89
+ plugin_class = _is_class_plugin(plugin_module)
90
+
91
+ if plugin_class:
92
+ # Handle new class-based plugins
93
+ plugin_instance = plugin_class(plugin_config)
94
+ app = plugin_instance.process(app)
95
+ logger.info(f"Processed class-based plugin: {plugin_name}")
96
+ elif hasattr(plugin_module, "process"):
97
+ # Handle legacy entrypoint plugins with deprecation warning
98
+ app = _process_legacy_plugin(plugin_module, app, plugin_config, plugin_name)
99
+ else:
100
+ raise PluginError(
101
+ f"Plugin {plugin_name} doesn't implement either the PluginBase interface "
102
+ f"or provide a process() function"
103
+ )
104
+
105
+ except Exception as e:
106
+ logger.error(f"Error processing plugin {plugin_name}: {e}")
107
+ raise PluginError(f"Error processing plugin {plugin_name}: {e}") from e
108
+
109
+ return app
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: platzky
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Not only blog engine
5
5
  License: MIT
6
6
  Requires-Python: >=3.10,<4.0
@@ -16,6 +16,7 @@ Requires-Dist: Flask-Minify (>=0.42,<0.43)
16
16
  Requires-Dist: Flask-WTF (>=1.2.1,<2.0.0)
17
17
  Requires-Dist: PyYAML (>=6.0,<7.0)
18
18
  Requires-Dist: aiohttp (>=3.9.5,<4.0.0)
19
+ Requires-Dist: deprecation (>=2.1.0,<3.0.0)
19
20
  Requires-Dist: google-cloud-storage (>=2.5.0,<3.0.0)
20
21
  Requires-Dist: gql (>=3.4.0,<4.0.0)
21
22
  Requires-Dist: humanize (>=4.9.0,<5.0.0)
@@ -1,20 +1,26 @@
1
- platzky/__init__.py,sha256=cEAqMh-FU8mbfCzFQaWMhKX4lDjoxDiQ9S4hTNsSOMg,160
1
+ platzky/__init__.py,sha256=IhL91rSWxIIJQNfVsqJ1d4yY5D2WyWcefo4Xv2aX_lo,180
2
+ platzky/admin/admin.py,sha256=nQq0IcBhrcX6S4gd71MejOcc2yizVv20UmF4ZRvZnBk,1019
3
+ platzky/admin/templates/admin.html,sha256=aIeQI9lSFvj6kwZg8U_AE7VSiVCxZeUdB_gLXzZDU20,778
4
+ platzky/admin/templates/login.html,sha256=a8dpJabAjvKyJZt9wKt9GtEO2XShuvo2m6BvZqDH6bU,391
5
+ platzky/admin/templates/module.html,sha256=WuQZxKQDD4INl-QF2uiKHf9Fmf2h7cEW9RLe1nWKC8k,175
2
6
  platzky/blog/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
7
  platzky/blog/blog.py,sha256=caBUewnwd6QrJDv20m4JDfDDjiVu7hM0AJnoTyCdwM4,3009
4
8
  platzky/blog/comment_form.py,sha256=4lkNJ_S_2DZmJBbz-NPDqahvy2Zz5AGNH2spFeGIop4,513
5
9
  platzky/config.py,sha256=M3gmZI9yI-ThgmTA4RKsAPcnJwJjcWhXipYzq3hO-Hk,2346
6
10
  platzky/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- platzky/db/db.py,sha256=W1EYQOrYaQI-Uon1IAJfD_1gmju2V_0yfo0hc8swUow,2790
11
+ platzky/db/db.py,sha256=o3jXcA97MwOepJhxtmXpyfDATRcMcJmX6O1Bro5-Rkw,2796
8
12
  platzky/db/db_loader.py,sha256=CuEiXxhIa4bFMm0vi7ugzm7j3WycilGRKCU6smgIImE,905
9
- platzky/db/google_json_db.py,sha256=IgfCER7oJ4I_WD4TjhvFFL0voUj6EfeoaVWdoEcHTdA,1499
10
- platzky/db/graph_ql_db.py,sha256=EjM9MfHOoEngJI6tFXC1JDrsK3kl-tkUXd7TwH2QCZc,8623
11
- platzky/db/json_db.py,sha256=3heiXVhZIWZB6byhnbOtGhnI-59ixN9spz24co4bvAk,3681
13
+ platzky/db/google_json_db.py,sha256=phRW8196o3lXxO3oSBAMMXfbOKR3K2MGkzF6w41SPBc,1305
14
+ platzky/db/graph_ql_db.py,sha256=aGE1glBmLmx4mE1aysGe6sl0lP2uG89LUnu2hmkdvqk,8528
15
+ platzky/db/json_db.py,sha256=J3sKykFLIv4tors0kEYF55SHLviLhHg8m-2fljXvqFI,3756
12
16
  platzky/db/json_file_db.py,sha256=UQ8TadELmqOzj_tgNfmzhtCkDkMAgcB9vaUy0GQXUY4,1010
17
+ platzky/engine.py,sha256=x6cP1oCaqqamfFgDdup7R9pe8z1KafdbNvrcUEOX7Ns,1897
13
18
  platzky/locale/en/LC_MESSAGES/messages.po,sha256=WaZGlFAegKRq7CSz69dWKic-mKvQFhVvssvExxNmGaU,1400
14
19
  platzky/locale/pl/LC_MESSAGES/messages.po,sha256=sUPxMKDeEOoZ5UIg94rGxZD06YVWiAMWIby2XE51Hrc,1624
15
20
  platzky/models.py,sha256=-IIlyeLzACeTUpzuzvzJYxtT57E6wRiERoRgXJYMMtY,1502
16
- platzky/platzky.py,sha256=A_ku8ZFseCde12vXL9PLNn9ybMszXDcBIqZbWj1rxMo,4996
17
- platzky/plugin_loader.py,sha256=TkeBYa4DrkUZ2lSJtIY5YKJEgtJvOCiXHhav_K8RaWs,1162
21
+ platzky/platzky.py,sha256=VBLN71eq81EDV5qQYwKUX_InQffmrouAXxblyoZpb-4,3666
22
+ platzky/plugin/plugin.py,sha256=tV8aobIzMDJe1frKUAi4kLbrTAIS0FWE3oYpktSo6Ug,1633
23
+ platzky/plugin/plugin_loader.py,sha256=MeQ8LNbrOomwXgc1ISHuyhjZd2mzYKen70eDShWs-Co,3497
18
24
  platzky/seo/seo.py,sha256=N_MmAA4KJZmmrDUh0hYNtD8ycOwpNKow4gVSAv8V3N4,2631
19
25
  platzky/static/blog.css,sha256=TrppzgQbj4UtuTufDCdblyNTVAqgIbhD66Cziyv_xnY,7893
20
26
  platzky/static/styles.css,sha256=U5ddGIK-VcGRJZ3BdOpMp0pR__k6rNEMsuQXkP4tFQ0,686
@@ -30,6 +36,6 @@ platzky/templates/post.html,sha256=GSgjIZsOQKtNx3cEbquSjZ5L4whPnG6MzRyoq9k4B8Q,1
30
36
  platzky/templates/robots.txt,sha256=2_j2tiYtYJnzZUrANiX9pvBxyw5Dp27fR_co18BPEJ0,116
31
37
  platzky/templates/sitemap.xml,sha256=iIJZ91_B5ZuNLCHsRtsGKZlBAXojOTP8kffqKLacgvs,578
32
38
  platzky/www_handler.py,sha256=pF6Rmvem1sdVqHD7z3RLrDuG-CwAqfGCti50_NPsB2w,725
33
- platzky-0.3.0.dist-info/METADATA,sha256=EhwOCjLEsHFcLEyM-IQasGVn8VKRX1_ZIeht_vAuE38,1642
34
- platzky-0.3.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
35
- platzky-0.3.0.dist-info/RECORD,,
39
+ platzky-0.3.1.dist-info/METADATA,sha256=iHkJnppWm5npC0Y-fJQywiO9toIVeoxQdbH0S3cAGhk,1686
40
+ platzky-0.3.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
41
+ platzky-0.3.1.dist-info/RECORD,,
platzky/plugin_loader.py DELETED
@@ -1,43 +0,0 @@
1
- import importlib.util
2
- import logging
3
-
4
- logger = logging.getLogger(__name__)
5
-
6
-
7
- class PluginError(Exception):
8
- pass
9
-
10
-
11
- def find_plugin(plugin_name):
12
- """Find plugin by name and return it as module.
13
- :param plugin_name: name of plugin to find
14
- :raises PluginError: if plugin cannot be imported
15
- :return: module of plugin
16
- """
17
- try:
18
- return importlib.import_module(f"platzky_{plugin_name}")
19
- except ImportError as e:
20
- raise PluginError(
21
- f"Plugin {plugin_name} not found. Ensure it's installed and follows "
22
- f"the 'platzky_<plugin_name>' naming convention"
23
- ) from e
24
-
25
-
26
- def plugify(app):
27
- """Load plugins and run their entrypoints.
28
- :param app: Flask app
29
- :return: Flask app
30
- """
31
-
32
- plugins_data = app.db.get_plugins_data()
33
-
34
- for plugin_data in plugins_data:
35
- plugin_config = plugin_data["config"]
36
- plugin_name = plugin_data["name"]
37
- try:
38
- plugin = find_plugin(plugin_name)
39
- plugin.process(app, plugin_config)
40
- except Exception as e:
41
- raise PluginError(f"Error processing plugin {plugin_name}: {e}") from e
42
-
43
- return app