Pyjoyment 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 (200) hide show
  1. Pyjo/App/ASGI.py +735 -0
  2. Pyjo/App/CGI.py +773 -0
  3. Pyjo/App/FastCGI.py +631 -0
  4. Pyjo/App/Lambda.py +987 -0
  5. Pyjo/App/WSGI.py +427 -0
  6. Pyjo/App/__init__.py +409 -0
  7. Pyjo/Asset/File.py +377 -0
  8. Pyjo/Asset/Memory.py +235 -0
  9. Pyjo/Asset/__init__.py +200 -0
  10. Pyjo/Base.py +215 -0
  11. Pyjo/Cache.py +119 -0
  12. Pyjo/Collection.py +570 -0
  13. Pyjo/Content/MultiPart.py +325 -0
  14. Pyjo/Content/Single.py +193 -0
  15. Pyjo/Content/__init__.py +806 -0
  16. Pyjo/Cookie/Request.py +90 -0
  17. Pyjo/Cookie/Response.py +294 -0
  18. Pyjo/Cookie/__init__.py +143 -0
  19. Pyjo/DOM/CSS.py +1019 -0
  20. Pyjo/DOM/HTML.py +550 -0
  21. Pyjo/DOM/__init__.py +1329 -0
  22. Pyjo/Date.py +294 -0
  23. Pyjo/EventEmitter.py +522 -0
  24. Pyjo/Exception.py +494 -0
  25. Pyjo/File.py +959 -0
  26. Pyjo/GetOpt.py +605 -0
  27. Pyjo/Headers.py +760 -0
  28. Pyjo/HelloWorld.py +77 -0
  29. Pyjo/Home.py +109 -0
  30. Pyjo/IOLoop/ChildProcess.py +591 -0
  31. Pyjo/IOLoop/Client.py +736 -0
  32. Pyjo/IOLoop/Datagram.py +982 -0
  33. Pyjo/IOLoop/Messages.py +664 -0
  34. Pyjo/IOLoop/Server.py +458 -0
  35. Pyjo/IOLoop/Stdio.py +446 -0
  36. Pyjo/IOLoop/Stream.py +644 -0
  37. Pyjo/IOLoop/Subprocess.py +419 -0
  38. Pyjo/IOLoop/TLS.py +360 -0
  39. Pyjo/IOLoop/__init__.py +1036 -0
  40. Pyjo/IOLoop/certs/README.md +41 -0
  41. Pyjo/IOLoop/certs/ca.crt +20 -0
  42. Pyjo/IOLoop/certs/server.crt +21 -0
  43. Pyjo/IOLoop/certs/server.key +28 -0
  44. Pyjo/JSON/Pointer.py +135 -0
  45. Pyjo/JSON/RPC.py +772 -0
  46. Pyjo/JSON/Schema.py +2506 -0
  47. Pyjo/JSON/__init__.py +573 -0
  48. Pyjo/Loader.py +342 -0
  49. Pyjo/Log.py +723 -0
  50. Pyjo/Message/Request.py +725 -0
  51. Pyjo/Message/Response.py +476 -0
  52. Pyjo/Message/__init__.py +830 -0
  53. Pyjo/Parameters.py +472 -0
  54. Pyjo/Path.py +419 -0
  55. Pyjo/Promise.py +894 -0
  56. Pyjo/Prove.py +1305 -0
  57. Pyjo/Reactor/Asyncio.py +854 -0
  58. Pyjo/Reactor/Poll.py +439 -0
  59. Pyjo/Reactor/__init__.py +525 -0
  60. Pyjo/SSE.py +119 -0
  61. Pyjo/Server/ASGI.py +486 -0
  62. Pyjo/Server/CGI.py +259 -0
  63. Pyjo/Server/Daemon.py +1007 -0
  64. Pyjo/Server/FastCGI.py +517 -0
  65. Pyjo/Server/Hot/__init__.py +687 -0
  66. Pyjo/Server/Hot/__main__.py +5 -0
  67. Pyjo/Server/Lambda.py +641 -0
  68. Pyjo/Server/Prefork.py +917 -0
  69. Pyjo/Server/Prethread.py +394 -0
  70. Pyjo/Server/Reload/Backend/Poll.py +114 -0
  71. Pyjo/Server/Reload/Backend/__init__.py +126 -0
  72. Pyjo/Server/Reload/__init__.py +482 -0
  73. Pyjo/Server/Reload/__main__.py +5 -0
  74. Pyjo/Server/Stdio.py +228 -0
  75. Pyjo/Server/WSGI.py +349 -0
  76. Pyjo/Server/__init__.py +396 -0
  77. Pyjo/String/Bytes.py +532 -0
  78. Pyjo/String/HTML.py +210 -0
  79. Pyjo/String/Mixin.py +333 -0
  80. Pyjo/String/Template.py +470 -0
  81. Pyjo/String/Unicode.py +553 -0
  82. Pyjo/String/__init__.py +0 -0
  83. Pyjo/TOML.py +232 -0
  84. Pyjo/Template.py +1290 -0
  85. Pyjo/Test/Pyjo.py +1454 -0
  86. Pyjo/Test/__init__.py +1233 -0
  87. Pyjo/Test/pytest_plugin.py +305 -0
  88. Pyjo/Transaction/HTTP.py +374 -0
  89. Pyjo/Transaction/WebSocket.py +709 -0
  90. Pyjo/Transaction/__init__.py +429 -0
  91. Pyjo/URL/Template.py +459 -0
  92. Pyjo/URL/__init__.py +651 -0
  93. Pyjo/Upload.py +139 -0
  94. Pyjo/UserAgent/CookieJar.py +391 -0
  95. Pyjo/UserAgent/Proxy.py +138 -0
  96. Pyjo/UserAgent/Server.py +239 -0
  97. Pyjo/UserAgent/Transactor.py +766 -0
  98. Pyjo/UserAgent/__init__.py +1243 -0
  99. Pyjo/Util.py +3567 -0
  100. Pyjo/WebSocket.py +332 -0
  101. Pyjo/YAML.py +1167 -0
  102. Pyjo/__init__.py +441 -0
  103. Pyjo/__main__.py +35 -0
  104. Pyjo/py.typed +0 -0
  105. Pyjoyment/Command/Author/__init__.py +20 -0
  106. Pyjoyment/Command/Author/generate/__init__.py +106 -0
  107. Pyjoyment/Command/Author/generate/app.py +299 -0
  108. Pyjoyment/Command/Author/generate/dockerfile.py +281 -0
  109. Pyjoyment/Command/Author/generate/kubernetes.py +514 -0
  110. Pyjoyment/Command/Author/generate/lambda_zip.py +372 -0
  111. Pyjoyment/Command/Author/generate/lite_app.py +113 -0
  112. Pyjoyment/Command/Author/generate/plugin.py +267 -0
  113. Pyjoyment/Command/Author/generate/pyproject.py +123 -0
  114. Pyjoyment/Command/Author/inflate.py +101 -0
  115. Pyjoyment/Command/__init__.py +332 -0
  116. Pyjoyment/Command/asgi.py +92 -0
  117. Pyjoyment/Command/cgi.py +90 -0
  118. Pyjoyment/Command/daemon.py +160 -0
  119. Pyjoyment/Command/eval.py +128 -0
  120. Pyjoyment/Command/fastcgi.py +99 -0
  121. Pyjoyment/Command/get.py +305 -0
  122. Pyjoyment/Command/lambda.py +117 -0
  123. Pyjoyment/Command/prefork.py +181 -0
  124. Pyjoyment/Command/prethread.py +126 -0
  125. Pyjoyment/Command/routes.py +133 -0
  126. Pyjoyment/Command/stdio.py +92 -0
  127. Pyjoyment/Command/version.py +141 -0
  128. Pyjoyment/Command/wsgi.py +93 -0
  129. Pyjoyment/Commands.py +546 -0
  130. Pyjoyment/Controller.py +1307 -0
  131. Pyjoyment/HelloWorld.py +56 -0
  132. Pyjoyment/Lite.py +494 -0
  133. Pyjoyment/Plugin/AllowedHosts.py +205 -0
  134. Pyjoyment/Plugin/Config.py +248 -0
  135. Pyjoyment/Plugin/DefaultHelpers.py +1202 -0
  136. Pyjoyment/Plugin/EPLRenderer.py +134 -0
  137. Pyjoyment/Plugin/EPRenderer.py +212 -0
  138. Pyjoyment/Plugin/HeaderCondition.py +98 -0
  139. Pyjoyment/Plugin/Health.py +325 -0
  140. Pyjoyment/Plugin/JSONConfig.py +172 -0
  141. Pyjoyment/Plugin/Mount.py +223 -0
  142. Pyjoyment/Plugin/PyRenderer.py +209 -0
  143. Pyjoyment/Plugin/TOMLConfig.py +141 -0
  144. Pyjoyment/Plugin/TagHelpers.py +959 -0
  145. Pyjoyment/Plugin/YAMLConfig.py +178 -0
  146. Pyjoyment/Plugin/__init__.py +80 -0
  147. Pyjoyment/Plugins.py +215 -0
  148. Pyjoyment/Renderer.py +673 -0
  149. Pyjoyment/Routes/Match.py +251 -0
  150. Pyjoyment/Routes/Pattern.py +443 -0
  151. Pyjoyment/Routes/Route.py +827 -0
  152. Pyjoyment/Routes/__init__.py +419 -0
  153. Pyjoyment/Sessions.py +255 -0
  154. Pyjoyment/Static.py +421 -0
  155. Pyjoyment/Types.py +238 -0
  156. Pyjoyment/Validator/Validation.py +395 -0
  157. Pyjoyment/Validator/__init__.py +304 -0
  158. Pyjoyment/__init__.py +1083 -0
  159. Pyjoyment/__main__.py +5 -0
  160. Pyjoyment/py.typed +0 -0
  161. Pyjoyment/resources/public/favicon.ico +0 -0
  162. Pyjoyment/resources/public/favicon.svg +345 -0
  163. Pyjoyment/resources/public/pyjo/bootstrap/LICENSE +21 -0
  164. Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.bundle.min.js.map +1 -0
  165. Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.css +6 -0
  166. Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.js +7 -0
  167. Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.min.css.map +1 -0
  168. Pyjoyment/resources/public/pyjo/failunicat.png +0 -0
  169. Pyjoyment/resources/public/pyjo/failunicat.svg +50 -0
  170. Pyjoyment/resources/public/pyjo/highlight.js/LICENSE +29 -0
  171. Pyjoyment/resources/public/pyjo/highlight.js/highlight-mojo-dark.css +56 -0
  172. Pyjoyment/resources/public/pyjo/highlight.js/highlight.min.js +1262 -0
  173. Pyjoyment/resources/public/pyjo/highlight.js/pyjoyment.min.js +1 -0
  174. Pyjoyment/resources/public/pyjo/logo-black-4x.png +0 -0
  175. Pyjoyment/resources/public/pyjo/logo-black-4x.svg +346 -0
  176. Pyjoyment/resources/public/pyjo/logo-white-2x.png +0 -0
  177. Pyjoyment/resources/public/pyjo/logo-white-2x.svg +346 -0
  178. Pyjoyment/resources/public/pyjo/logo-white-4x.png +0 -0
  179. Pyjoyment/resources/public/pyjo/logo-white-4x.svg +346 -0
  180. Pyjoyment/resources/public/pyjo/logo-white.png +0 -0
  181. Pyjoyment/resources/public/pyjo/logo-white.svg +346 -0
  182. Pyjoyment/resources/public/pyjo/logo.png +0 -0
  183. Pyjoyment/resources/public/pyjo/logo.svg +346 -0
  184. Pyjoyment/resources/public/pyjo/notfound.png +0 -0
  185. Pyjoyment/resources/public/pyjo/notfound.svg +3 -0
  186. Pyjoyment/resources/public/pyjo/nounicat.png +0 -0
  187. Pyjoyment/resources/public/pyjo/nounicat.svg +5 -0
  188. Pyjoyment/resources/public/pyjo/pinstripe-dark.png +0 -0
  189. Pyjoyment/resources/public/pyjo/pinstripe-dark.svg +4 -0
  190. Pyjoyment/resources/public/pyjo/pinstripe-light.png +0 -0
  191. Pyjoyment/resources/public/pyjo/pinstripe-light.svg +4 -0
  192. Pyjoyment/resources/public/pyjo/pyjo.css +204 -0
  193. Pyjoyment/resources/templates/pyjo/debug.html.ep +346 -0
  194. Pyjoyment/resources/templates/pyjo/exception.html.ep +32 -0
  195. Pyjoyment/resources/templates/pyjo/not_found.html.ep +45 -0
  196. pyjoyment-0.1.0.dist-info/METADATA +376 -0
  197. pyjoyment-0.1.0.dist-info/RECORD +200 -0
  198. pyjoyment-0.1.0.dist-info/WHEEL +4 -0
  199. pyjoyment-0.1.0.dist-info/entry_points.txt +8 -0
  200. pyjoyment-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,178 @@
1
+ """
2
+ Pyjoyment.Plugin.YAMLConfig - YAML configuration plugin
3
+ =======================================================
4
+ ::
5
+
6
+ # myapp.yml (it's just YAML with embedded Python)
7
+ ---
8
+ foo: bar
9
+ baz:
10
+ - ♥
11
+ music_dir: <%= app.home.child('music') %>
12
+
13
+ # Pyjoyment
14
+ config = app.plugin('YAMLConfig')
15
+ print(config['foo'])
16
+
17
+ # Pyjoyment.Lite
18
+ config = plugin('YAMLConfig')
19
+ print(config['foo'])
20
+
21
+ # foo.html.ep
22
+ %= config()['foo']
23
+
24
+ # The configuration is available application-wide
25
+ config = app.config()
26
+ print(config['foo'])
27
+
28
+ # Everything can be customized with options
29
+ config = plugin('YAMLConfig', file='/etc/myapp.conf')
30
+
31
+ :mod:`Pyjoyment.Plugin.YAMLConfig` is a YAML configuration plugin that
32
+ preprocesses its input with :mod:`Pyjo.Template`. By default it uses
33
+ :mod:`Pyjo.YAML` for parsing, which is not the best YAML module available, but
34
+ good enough for most config files. If you need something more correct you can
35
+ use a different module like PyYAML with the ``module`` option.
36
+
37
+ The application object can be accessed via ``app``. A default configuration
38
+ filename in the application home directory will be generated from the value
39
+ of :attr:`Pyjoyment.Pyjoyment_App.moniker` (``$moniker.yml``). You can extend
40
+ the normal configuration file ``$moniker.yml`` with ``mode`` specific ones
41
+ like ``$moniker.$mode.yml``, which will be detected automatically.
42
+
43
+ These configuration values are currently reserved:
44
+
45
+ ``config_override``
46
+ If this configuration value has been set in
47
+ :meth:`Pyjoyment.Pyjoyment_App.config` when this plugin is loaded, it will
48
+ not do anything besides loading deployment specific plugins.
49
+
50
+ ``plugins`` ::
51
+
52
+ plugins:
53
+ - SetUserGroup:
54
+ user: sri
55
+ group: staff
56
+
57
+ One or more deployment specific plugins that should be loaded right after
58
+ this plugin has been loaded.
59
+
60
+ The code of this plugin is a good example for learning to build new plugins,
61
+ you're welcome to fork it.
62
+
63
+ See :mod:`Pyjoyment.Plugins` for a list of plugins that are available by
64
+ default.
65
+
66
+ Options
67
+ -------
68
+
69
+ :mod:`Pyjoyment.Plugin.YAMLConfig` inherits all options from
70
+ :mod:`Pyjoyment.Plugin.JSONConfig` and supports the following new ones.
71
+
72
+ module ::
73
+
74
+ # Pyjoyment.Lite
75
+ plugin('YAMLConfig', module='yaml')
76
+ plugin('YAMLConfig', module=yaml.safe_load)
77
+
78
+ Alternative YAML module to use for parsing, whose function ``safe_load``, or
79
+ ``load``, takes a string, or such a function.
80
+
81
+ See also
82
+ --------
83
+
84
+ :mod:`Pyjoyment`, https://mojolicious.org.
85
+
86
+ Ported from `Mojolicious::Plugin::NotYAMLConfig
87
+ <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojolicious/Plugin/NotYAMLConfig.pm>`_ of Mojolicious 9.49.
88
+
89
+ Classes
90
+ -------
91
+ """
92
+
93
+ # Renamed from Mojolicious: YAMLConfig, where Mojo has NotYAMLConfig, as the file is YAML once its template is rendered,
94
+ # as the files of JSONConfig and TOMLConfig are JSON and TOML
95
+
96
+ import Pyjo.Exception
97
+ import Pyjo.YAML
98
+ import Pyjoyment.Plugin.JSONConfig
99
+
100
+ import importlib
101
+
102
+ from collections.abc import Callable
103
+ from typing import TYPE_CHECKING, Any, cast
104
+
105
+
106
+ if TYPE_CHECKING:
107
+ import Pyjoyment
108
+
109
+
110
+ class Pyjoyment_Plugin_YAMLConfig(Pyjoyment.Plugin.JSONConfig.object):
111
+ """
112
+ :mod:`Pyjoyment.Plugin.YAMLConfig` inherits all methods from
113
+ :mod:`Pyjoyment.Plugin.JSONConfig` and implements the following new ones.
114
+ """
115
+
116
+ def __init__(self) -> None:
117
+ super().__init__()
118
+ self._yaml: Callable[[str], Any] = Pyjo.YAML.load
119
+
120
+ def parse(self, content: str, file: str, conf: dict[str, Any], app: 'Pyjoyment.object') -> dict[str, Any]:
121
+ """::
122
+
123
+ plugin.parse(content, file, conf, app)
124
+
125
+ Process content with
126
+ :meth:`~Pyjoyment.Plugin.JSONConfig.Pyjoyment_Plugin_JSONConfig.render`
127
+ and parse it with :mod:`Pyjo.YAML`. ::
128
+
129
+ def parse(self, content, file, conf, app):
130
+ ...
131
+ content = self.render(content, file, conf, app)
132
+ ...
133
+ return config
134
+ """
135
+ try:
136
+ config = self._yaml(self.render(content, file, conf, app))
137
+ except Exception as e:
138
+ raise Pyjo.Exception.new(f'Can\'t load configuration from file "{file}": {e}') from e
139
+ if not isinstance(config, dict):
140
+ raise Pyjo.Exception.new(f'Configuration file "{file}" did not return a YAML mapping')
141
+ return cast(dict[str, Any], config)
142
+
143
+ def register(self, app: 'Pyjoyment.object', conf: dict[str, Any] | None = None) -> dict[str, Any]:
144
+ """::
145
+
146
+ config = plugin.register(Pyjoyment.new())
147
+ config = plugin.register(Pyjoyment.new(), {'file': '/etc/foo.conf'})
148
+
149
+ Register plugin in :mod:`Pyjoyment` application and merge
150
+ configuration.
151
+ """
152
+ conf = {'ext': 'yml', **(conf or {})}
153
+
154
+ self._yaml = Pyjo.YAML.load
155
+ if module := conf.get('module'):
156
+ if (load := _load(module)) is None:
157
+ raise Pyjo.Exception.new(f'YAML module {module} has no Load function')
158
+ self._yaml = load
159
+
160
+ return super().register(app, conf)
161
+
162
+
163
+ # Not in Mojolicious: a function of a module, safe_load or load, as the YAML modules of Python name it, or the function
164
+ # itself, where Mojo takes the function Load of a module
165
+ def _load(module: Any) -> Callable[[str], Any] | None:
166
+ if callable(module):
167
+ return cast(Callable[[str], Any], module)
168
+ try:
169
+ mod = importlib.import_module(str(module))
170
+ except ImportError:
171
+ return None
172
+ load = getattr(mod, 'safe_load', None) or getattr(mod, 'load', None)
173
+ return cast(Callable[[str], Any], load) if callable(load) else None
174
+
175
+
176
+ new = Pyjoyment_Plugin_YAMLConfig.new
177
+ object = Pyjoyment_Plugin_YAMLConfig
178
+ YAMLConfig = Pyjoyment_Plugin_YAMLConfig
@@ -0,0 +1,80 @@
1
+ """
2
+ Pyjoyment.Plugin - Plugin base class
3
+ ====================================
4
+ ::
5
+
6
+ # CamelCase plugin name
7
+ from Pyjoyment.Plugin import Plugin
8
+
9
+ class Pyjoyment_Plugin_MyPlugin(Plugin):
10
+ def register(self, app, conf):
11
+ # Magic here! :)
12
+ ...
13
+
14
+ object = Pyjoyment_Plugin_MyPlugin
15
+
16
+ # Or import the module, as in Google Python Style Guide
17
+
18
+ # CamelCase plugin name
19
+ import Pyjoyment.Plugin
20
+
21
+ class Pyjoyment_Plugin_MyPlugin(Pyjoyment.Plugin.object):
22
+ def register(self, app, conf):
23
+ # Magic here! :)
24
+ ...
25
+
26
+ object = Pyjoyment_Plugin_MyPlugin
27
+
28
+ :mod:`Pyjoyment.Plugin` is an abstract base class for :mod:`Pyjoyment`
29
+ plugins.
30
+
31
+ See :mod:`Pyjoyment.Plugins` for a list of plugins that are available by
32
+ default.
33
+
34
+ A plugin of another distribution is a module in the namespace
35
+ ``Pyjoyment.Plugin``, which :func:`pkgutil.extend_path` keeps open, and the
36
+ class that the module names ``object``.
37
+
38
+ See also
39
+ --------
40
+
41
+ :mod:`Pyjoyment`, https://mojolicious.org.
42
+
43
+ Ported from `Mojolicious::Plugin <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojolicious/Plugin.pm>`_
44
+ of Mojolicious 9.49.
45
+ """
46
+
47
+ import Pyjo.Base
48
+
49
+ from pkgutil import extend_path
50
+ from typing import TYPE_CHECKING, Any
51
+
52
+
53
+ if TYPE_CHECKING:
54
+ import Pyjoyment
55
+
56
+
57
+ class Pyjoyment_Plugin(Pyjo.Base.object):
58
+ """
59
+ :mod:`Pyjoyment.Plugin` inherits all methods from :mod:`Pyjo.Base` and
60
+ implements the following new ones.
61
+ """
62
+
63
+ def register(self, app: 'Pyjoyment.object', conf: dict[str, Any]) -> Any:
64
+ """::
65
+
66
+ plugin.register(Pyjoyment.new(), {})
67
+ plugin.register(Pyjoyment.new(), {'foo': 'bar'})
68
+
69
+ This method will be called by :mod:`Pyjoyment.Plugins` at startup time.
70
+ Meant to be overloaded in a subclass.
71
+ """
72
+ raise NotImplementedError('Method "register" not implemented by subclass')
73
+
74
+
75
+ # Not in Mojolicious: a namespace that other distributions can add plugins to
76
+ __path__ = extend_path(__path__, __name__)
77
+
78
+ new = Pyjoyment_Plugin.new
79
+ object = Pyjoyment_Plugin
80
+ Plugin = Pyjoyment_Plugin
Pyjoyment/Plugins.py ADDED
@@ -0,0 +1,215 @@
1
+ """
2
+ Pyjoyment.Plugins - Plugin manager
3
+ ==================================
4
+ ::
5
+
6
+ from Pyjoyment.Plugins import Plugins
7
+
8
+ plugins = Plugins()
9
+ plugins.namespaces.append('MyApp.Plugin')
10
+
11
+ # Or import the module, as in Google Python Style Guide
12
+
13
+ import Pyjoyment.Plugins
14
+
15
+ plugins = Pyjoyment.Plugins.new()
16
+ plugins.namespaces.append('MyApp.Plugin')
17
+
18
+ :mod:`Pyjoyment.Plugins` is the plugin manager of :mod:`Pyjoyment`.
19
+
20
+ Plugins
21
+ -------
22
+
23
+ The following plugins are included in the :mod:`Pyjoyment` distribution as
24
+ examples.
25
+
26
+ :mod:`Pyjoyment.Plugin.AllowedHosts`
27
+ Validation of ``Host`` and ``Origin`` against DNS rebinding.
28
+
29
+ :mod:`Pyjoyment.Plugin.Config`
30
+ Python-ish configuration files.
31
+
32
+ :mod:`Pyjoyment.Plugin.DefaultHelpers`
33
+ General purpose helper collection, loaded automatically.
34
+
35
+ :mod:`Pyjoyment.Plugin.EPLRenderer`
36
+ Renderer for plain embedded Python templates, loaded automatically.
37
+
38
+ :mod:`Pyjoyment.Plugin.EPRenderer`
39
+ Renderer for more sophisticated embedded Python templates, loaded
40
+ automatically.
41
+
42
+ :mod:`Pyjoyment.Plugin.Health`
43
+ Liveness and readiness of containers and orchestrators.
44
+
45
+ :mod:`Pyjoyment.Plugin.HeaderCondition`
46
+ Route condition for all kinds of headers, loaded automatically.
47
+
48
+ :mod:`Pyjoyment.Plugin.JSONConfig`
49
+ JSON configuration files.
50
+
51
+ :mod:`Pyjoyment.Plugin.Mount`
52
+ Mount whole :mod:`Pyjoyment` applications.
53
+
54
+ :mod:`Pyjoyment.Plugin.PyRenderer`
55
+ Renderer for template strings, loaded automatically.
56
+
57
+ :mod:`Pyjoyment.Plugin.TagHelpers`
58
+ Template specific helper collection, loaded automatically.
59
+
60
+ :mod:`Pyjoyment.Plugin.TOMLConfig`
61
+ TOML configuration files.
62
+
63
+ :mod:`Pyjoyment.Plugin.YAMLConfig`
64
+ YAML configuration files.
65
+
66
+ Events
67
+ ------
68
+
69
+ :mod:`Pyjoyment.Plugins` inherits all events from :mod:`Pyjo.EventEmitter`.
70
+
71
+ See also
72
+ --------
73
+
74
+ :mod:`Pyjoyment`, https://mojolicious.org.
75
+
76
+ Ported from `Mojolicious::Plugins <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojolicious/Plugins.pm>`_
77
+ of Mojolicious 9.49.
78
+ """
79
+
80
+ import Pyjo.EventEmitter
81
+ import Pyjo.Exception
82
+ import Pyjo.Loader
83
+ import Pyjoyment.Plugin
84
+
85
+ from Pyjo.Util import camelize
86
+
87
+ import re
88
+
89
+ from collections.abc import Callable
90
+ from typing import TYPE_CHECKING, Any, Self
91
+
92
+
93
+ if TYPE_CHECKING:
94
+ import Pyjoyment
95
+
96
+
97
+ class Pyjoyment_Plugins(Pyjo.EventEmitter.object):
98
+ """
99
+ :mod:`Pyjoyment.Plugins` inherits all methods from
100
+ :mod:`Pyjo.EventEmitter` and implements the following new ones.
101
+ """
102
+
103
+ def __init__(self) -> None:
104
+ """::
105
+
106
+ plugins = Pyjoyment.Plugins.new()
107
+
108
+ Construct a new :mod:`Pyjoyment.Plugins` object.
109
+ """
110
+ super().__init__()
111
+
112
+ self.namespaces = ['Pyjoyment.Plugin']
113
+ """::
114
+
115
+ namespaces = plugins.namespaces
116
+ plugins.namespaces = ['Pyjoyment.Plugin']
117
+
118
+ Namespaces to load plugins from, defaults to :mod:`Pyjoyment.Plugin`. ::
119
+
120
+ # Add another namespace to load plugins from
121
+ plugins.namespaces.append('MyApp.Plugin')
122
+ """
123
+
124
+ def emit_chain(self, name: str, *args: Any) -> Any:
125
+ """::
126
+
127
+ plugins.emit_chain('foo')
128
+ plugins.emit_chain('foo', 123)
129
+
130
+ Emit events as chained hooks.
131
+ """
132
+ wrapper: Callable[[], Any] | None = None
133
+ for cb in reversed(self.subscribers(name)):
134
+ wrapper = _wrap(cb, wrapper, args)
135
+
136
+ return wrapper() if wrapper is not None else None
137
+
138
+ def emit_hook(self, name: str, *args: Any) -> Self:
139
+ """::
140
+
141
+ plugins = plugins.emit_hook('foo')
142
+ plugins = plugins.emit_hook('foo', 123)
143
+
144
+ Emit events as hooks.
145
+ """
146
+ for cb in self.subscribers(name):
147
+ cb(*args)
148
+ return self
149
+
150
+ def emit_hook_reverse(self, name: str, *args: Any) -> Self:
151
+ """::
152
+
153
+ plugins = plugins.emit_hook_reverse('foo')
154
+ plugins = plugins.emit_hook_reverse('foo', 123)
155
+
156
+ Emit events as hooks in reverse order.
157
+ """
158
+ for cb in reversed(self.subscribers(name)):
159
+ cb(*args)
160
+ return self
161
+
162
+ def load_plugin(self, name: str) -> Pyjoyment.Plugin.object:
163
+ """::
164
+
165
+ plugin = plugins.load_plugin('some_thing')
166
+ plugin = plugins.load_plugin('SomeThing')
167
+ plugin = plugins.load_plugin('MyApp.Plugin.SomeThing')
168
+
169
+ Load a plugin from the configured namespaces or by full module name.
170
+ """
171
+ # Try all namespaces and full module name
172
+ suffix = camelize(name).replace('::', '.') if re.match(r'^[a-z]', name) else name
173
+ classes = [f'{namespace}.{suffix}' for namespace in self.namespaces]
174
+ for cls in [*classes, name]:
175
+ if (plugin := _load(cls)) is not None:
176
+ return plugin.new()
177
+
178
+ # Not found
179
+ raise Pyjo.Exception.new(f'Plugin "{name}" missing, maybe you need to install it?\n')
180
+
181
+ def register_plugin(
182
+ self, name: str, app: 'Pyjoyment.object', conf: dict[str, Any] | None = None, /, **values: Any
183
+ ) -> Any:
184
+ """::
185
+
186
+ plugins.register_plugin('some_thing', Pyjoyment.new())
187
+ plugins.register_plugin('some_thing', Pyjoyment.new(), foo=23)
188
+ plugins.register_plugin('some_thing', Pyjoyment.new(), {'foo': 23})
189
+ plugins.register_plugin('SomeThing', Pyjoyment.new())
190
+ plugins.register_plugin('SomeThing', Pyjoyment.new(), foo=23)
191
+ plugins.register_plugin('SomeThing', Pyjoyment.new(), {'foo': 23})
192
+ plugins.register_plugin('MyApp.Plugin.SomeThing', Pyjoyment.new())
193
+ plugins.register_plugin('MyApp.Plugin.SomeThing', Pyjoyment.new(), foo=23)
194
+ plugins.register_plugin('MyApp.Plugin.SomeThing', Pyjoyment.new(), {'foo': 23})
195
+
196
+ Load a plugin from the configured namespaces or by full module name and
197
+ run ``register``, optional arguments are passed through.
198
+ """
199
+ return self.load_plugin(name).register(app, {**(conf or {}), **values})
200
+
201
+
202
+ def _load(name: str) -> type[Pyjoyment.Plugin.object] | None:
203
+ if isinstance(e := Pyjo.Loader.load_class(name), Exception):
204
+ raise e
205
+ cls = Pyjo.Loader._class(name) # pyright: ignore[reportPrivateUsage]
206
+ return cls if cls is not None and issubclass(cls, Pyjoyment.Plugin.object) else None
207
+
208
+
209
+ def _wrap(cb: Callable[..., Any], next: Callable[[], Any] | None, args: tuple[Any, ...]) -> Callable[[], Any]:
210
+ return lambda: cb(next, *args)
211
+
212
+
213
+ new = Pyjoyment_Plugins.new
214
+ object = Pyjoyment_Plugins
215
+ Plugins = Pyjoyment_Plugins