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.
- Pyjo/App/ASGI.py +735 -0
- Pyjo/App/CGI.py +773 -0
- Pyjo/App/FastCGI.py +631 -0
- Pyjo/App/Lambda.py +987 -0
- Pyjo/App/WSGI.py +427 -0
- Pyjo/App/__init__.py +409 -0
- Pyjo/Asset/File.py +377 -0
- Pyjo/Asset/Memory.py +235 -0
- Pyjo/Asset/__init__.py +200 -0
- Pyjo/Base.py +215 -0
- Pyjo/Cache.py +119 -0
- Pyjo/Collection.py +570 -0
- Pyjo/Content/MultiPart.py +325 -0
- Pyjo/Content/Single.py +193 -0
- Pyjo/Content/__init__.py +806 -0
- Pyjo/Cookie/Request.py +90 -0
- Pyjo/Cookie/Response.py +294 -0
- Pyjo/Cookie/__init__.py +143 -0
- Pyjo/DOM/CSS.py +1019 -0
- Pyjo/DOM/HTML.py +550 -0
- Pyjo/DOM/__init__.py +1329 -0
- Pyjo/Date.py +294 -0
- Pyjo/EventEmitter.py +522 -0
- Pyjo/Exception.py +494 -0
- Pyjo/File.py +959 -0
- Pyjo/GetOpt.py +605 -0
- Pyjo/Headers.py +760 -0
- Pyjo/HelloWorld.py +77 -0
- Pyjo/Home.py +109 -0
- Pyjo/IOLoop/ChildProcess.py +591 -0
- Pyjo/IOLoop/Client.py +736 -0
- Pyjo/IOLoop/Datagram.py +982 -0
- Pyjo/IOLoop/Messages.py +664 -0
- Pyjo/IOLoop/Server.py +458 -0
- Pyjo/IOLoop/Stdio.py +446 -0
- Pyjo/IOLoop/Stream.py +644 -0
- Pyjo/IOLoop/Subprocess.py +419 -0
- Pyjo/IOLoop/TLS.py +360 -0
- Pyjo/IOLoop/__init__.py +1036 -0
- Pyjo/IOLoop/certs/README.md +41 -0
- Pyjo/IOLoop/certs/ca.crt +20 -0
- Pyjo/IOLoop/certs/server.crt +21 -0
- Pyjo/IOLoop/certs/server.key +28 -0
- Pyjo/JSON/Pointer.py +135 -0
- Pyjo/JSON/RPC.py +772 -0
- Pyjo/JSON/Schema.py +2506 -0
- Pyjo/JSON/__init__.py +573 -0
- Pyjo/Loader.py +342 -0
- Pyjo/Log.py +723 -0
- Pyjo/Message/Request.py +725 -0
- Pyjo/Message/Response.py +476 -0
- Pyjo/Message/__init__.py +830 -0
- Pyjo/Parameters.py +472 -0
- Pyjo/Path.py +419 -0
- Pyjo/Promise.py +894 -0
- Pyjo/Prove.py +1305 -0
- Pyjo/Reactor/Asyncio.py +854 -0
- Pyjo/Reactor/Poll.py +439 -0
- Pyjo/Reactor/__init__.py +525 -0
- Pyjo/SSE.py +119 -0
- Pyjo/Server/ASGI.py +486 -0
- Pyjo/Server/CGI.py +259 -0
- Pyjo/Server/Daemon.py +1007 -0
- Pyjo/Server/FastCGI.py +517 -0
- Pyjo/Server/Hot/__init__.py +687 -0
- Pyjo/Server/Hot/__main__.py +5 -0
- Pyjo/Server/Lambda.py +641 -0
- Pyjo/Server/Prefork.py +917 -0
- Pyjo/Server/Prethread.py +394 -0
- Pyjo/Server/Reload/Backend/Poll.py +114 -0
- Pyjo/Server/Reload/Backend/__init__.py +126 -0
- Pyjo/Server/Reload/__init__.py +482 -0
- Pyjo/Server/Reload/__main__.py +5 -0
- Pyjo/Server/Stdio.py +228 -0
- Pyjo/Server/WSGI.py +349 -0
- Pyjo/Server/__init__.py +396 -0
- Pyjo/String/Bytes.py +532 -0
- Pyjo/String/HTML.py +210 -0
- Pyjo/String/Mixin.py +333 -0
- Pyjo/String/Template.py +470 -0
- Pyjo/String/Unicode.py +553 -0
- Pyjo/String/__init__.py +0 -0
- Pyjo/TOML.py +232 -0
- Pyjo/Template.py +1290 -0
- Pyjo/Test/Pyjo.py +1454 -0
- Pyjo/Test/__init__.py +1233 -0
- Pyjo/Test/pytest_plugin.py +305 -0
- Pyjo/Transaction/HTTP.py +374 -0
- Pyjo/Transaction/WebSocket.py +709 -0
- Pyjo/Transaction/__init__.py +429 -0
- Pyjo/URL/Template.py +459 -0
- Pyjo/URL/__init__.py +651 -0
- Pyjo/Upload.py +139 -0
- Pyjo/UserAgent/CookieJar.py +391 -0
- Pyjo/UserAgent/Proxy.py +138 -0
- Pyjo/UserAgent/Server.py +239 -0
- Pyjo/UserAgent/Transactor.py +766 -0
- Pyjo/UserAgent/__init__.py +1243 -0
- Pyjo/Util.py +3567 -0
- Pyjo/WebSocket.py +332 -0
- Pyjo/YAML.py +1167 -0
- Pyjo/__init__.py +441 -0
- Pyjo/__main__.py +35 -0
- Pyjo/py.typed +0 -0
- Pyjoyment/Command/Author/__init__.py +20 -0
- Pyjoyment/Command/Author/generate/__init__.py +106 -0
- Pyjoyment/Command/Author/generate/app.py +299 -0
- Pyjoyment/Command/Author/generate/dockerfile.py +281 -0
- Pyjoyment/Command/Author/generate/kubernetes.py +514 -0
- Pyjoyment/Command/Author/generate/lambda_zip.py +372 -0
- Pyjoyment/Command/Author/generate/lite_app.py +113 -0
- Pyjoyment/Command/Author/generate/plugin.py +267 -0
- Pyjoyment/Command/Author/generate/pyproject.py +123 -0
- Pyjoyment/Command/Author/inflate.py +101 -0
- Pyjoyment/Command/__init__.py +332 -0
- Pyjoyment/Command/asgi.py +92 -0
- Pyjoyment/Command/cgi.py +90 -0
- Pyjoyment/Command/daemon.py +160 -0
- Pyjoyment/Command/eval.py +128 -0
- Pyjoyment/Command/fastcgi.py +99 -0
- Pyjoyment/Command/get.py +305 -0
- Pyjoyment/Command/lambda.py +117 -0
- Pyjoyment/Command/prefork.py +181 -0
- Pyjoyment/Command/prethread.py +126 -0
- Pyjoyment/Command/routes.py +133 -0
- Pyjoyment/Command/stdio.py +92 -0
- Pyjoyment/Command/version.py +141 -0
- Pyjoyment/Command/wsgi.py +93 -0
- Pyjoyment/Commands.py +546 -0
- Pyjoyment/Controller.py +1307 -0
- Pyjoyment/HelloWorld.py +56 -0
- Pyjoyment/Lite.py +494 -0
- Pyjoyment/Plugin/AllowedHosts.py +205 -0
- Pyjoyment/Plugin/Config.py +248 -0
- Pyjoyment/Plugin/DefaultHelpers.py +1202 -0
- Pyjoyment/Plugin/EPLRenderer.py +134 -0
- Pyjoyment/Plugin/EPRenderer.py +212 -0
- Pyjoyment/Plugin/HeaderCondition.py +98 -0
- Pyjoyment/Plugin/Health.py +325 -0
- Pyjoyment/Plugin/JSONConfig.py +172 -0
- Pyjoyment/Plugin/Mount.py +223 -0
- Pyjoyment/Plugin/PyRenderer.py +209 -0
- Pyjoyment/Plugin/TOMLConfig.py +141 -0
- Pyjoyment/Plugin/TagHelpers.py +959 -0
- Pyjoyment/Plugin/YAMLConfig.py +178 -0
- Pyjoyment/Plugin/__init__.py +80 -0
- Pyjoyment/Plugins.py +215 -0
- Pyjoyment/Renderer.py +673 -0
- Pyjoyment/Routes/Match.py +251 -0
- Pyjoyment/Routes/Pattern.py +443 -0
- Pyjoyment/Routes/Route.py +827 -0
- Pyjoyment/Routes/__init__.py +419 -0
- Pyjoyment/Sessions.py +255 -0
- Pyjoyment/Static.py +421 -0
- Pyjoyment/Types.py +238 -0
- Pyjoyment/Validator/Validation.py +395 -0
- Pyjoyment/Validator/__init__.py +304 -0
- Pyjoyment/__init__.py +1083 -0
- Pyjoyment/__main__.py +5 -0
- Pyjoyment/py.typed +0 -0
- Pyjoyment/resources/public/favicon.ico +0 -0
- Pyjoyment/resources/public/favicon.svg +345 -0
- Pyjoyment/resources/public/pyjo/bootstrap/LICENSE +21 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.bundle.min.js.map +1 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.css +6 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.js +7 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.min.css.map +1 -0
- Pyjoyment/resources/public/pyjo/failunicat.png +0 -0
- Pyjoyment/resources/public/pyjo/failunicat.svg +50 -0
- Pyjoyment/resources/public/pyjo/highlight.js/LICENSE +29 -0
- Pyjoyment/resources/public/pyjo/highlight.js/highlight-mojo-dark.css +56 -0
- Pyjoyment/resources/public/pyjo/highlight.js/highlight.min.js +1262 -0
- Pyjoyment/resources/public/pyjo/highlight.js/pyjoyment.min.js +1 -0
- Pyjoyment/resources/public/pyjo/logo-black-4x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-black-4x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white-2x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white-2x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white-4x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white-4x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo.png +0 -0
- Pyjoyment/resources/public/pyjo/logo.svg +346 -0
- Pyjoyment/resources/public/pyjo/notfound.png +0 -0
- Pyjoyment/resources/public/pyjo/notfound.svg +3 -0
- Pyjoyment/resources/public/pyjo/nounicat.png +0 -0
- Pyjoyment/resources/public/pyjo/nounicat.svg +5 -0
- Pyjoyment/resources/public/pyjo/pinstripe-dark.png +0 -0
- Pyjoyment/resources/public/pyjo/pinstripe-dark.svg +4 -0
- Pyjoyment/resources/public/pyjo/pinstripe-light.png +0 -0
- Pyjoyment/resources/public/pyjo/pinstripe-light.svg +4 -0
- Pyjoyment/resources/public/pyjo/pyjo.css +204 -0
- Pyjoyment/resources/templates/pyjo/debug.html.ep +346 -0
- Pyjoyment/resources/templates/pyjo/exception.html.ep +32 -0
- Pyjoyment/resources/templates/pyjo/not_found.html.ep +45 -0
- pyjoyment-0.1.0.dist-info/METADATA +376 -0
- pyjoyment-0.1.0.dist-info/RECORD +200 -0
- pyjoyment-0.1.0.dist-info/WHEEL +4 -0
- pyjoyment-0.1.0.dist-info/entry_points.txt +8 -0
- pyjoyment-0.1.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjoyment.Command - Command base class
|
|
3
|
+
======================================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
# Lowercase command name, in the module Pyjoyment.Command.mycommand
|
|
7
|
+
from Pyjoyment.Command import Command
|
|
8
|
+
|
|
9
|
+
from Pyjo.Util import extract_usage
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Pyjoyment_Command_mycommand(Command):
|
|
13
|
+
# Short description
|
|
14
|
+
description = 'My first Pyjoyment command'
|
|
15
|
+
|
|
16
|
+
# Usage message from the synopsis of the docstring of the module
|
|
17
|
+
usage = extract_usage()
|
|
18
|
+
|
|
19
|
+
def run(self, *args):
|
|
20
|
+
# Magic here! :)
|
|
21
|
+
...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
object = Pyjoyment_Command_mycommand
|
|
25
|
+
|
|
26
|
+
# Or import the module, as in Google Python Style Guide
|
|
27
|
+
|
|
28
|
+
# Lowercase command name, in the module Pyjoyment.Command.mycommand
|
|
29
|
+
import Pyjoyment.Command
|
|
30
|
+
|
|
31
|
+
from Pyjo.Util import extract_usage
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Pyjoyment_Command_mycommand(Pyjoyment.Command.object):
|
|
35
|
+
# Short description
|
|
36
|
+
description = 'My first Pyjoyment command'
|
|
37
|
+
|
|
38
|
+
# Usage message from the synopsis of the docstring of the module
|
|
39
|
+
usage = extract_usage()
|
|
40
|
+
|
|
41
|
+
def run(self, *args):
|
|
42
|
+
# Magic here! :)
|
|
43
|
+
...
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
object = Pyjoyment_Command_mycommand
|
|
47
|
+
|
|
48
|
+
# The synopsis in the docstring of the module
|
|
49
|
+
\"\"\"
|
|
50
|
+
Pyjoyment.Command.mycommand - My command
|
|
51
|
+
========================================
|
|
52
|
+
::
|
|
53
|
+
|
|
54
|
+
Usage: APPLICATION mycommand [OPTIONS]
|
|
55
|
+
|
|
56
|
+
Options:
|
|
57
|
+
-s, --something Does something
|
|
58
|
+
\"\"\"
|
|
59
|
+
|
|
60
|
+
:mod:`Pyjoyment.Command` is an abstract base class for :mod:`Pyjoyment`
|
|
61
|
+
commands.
|
|
62
|
+
|
|
63
|
+
See :mod:`Pyjoyment.Commands` for a list of commands that are available by
|
|
64
|
+
default.
|
|
65
|
+
|
|
66
|
+
See also
|
|
67
|
+
--------
|
|
68
|
+
|
|
69
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
70
|
+
|
|
71
|
+
Ported from `Mojolicious::Command <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojolicious/Command.pm>`_
|
|
72
|
+
of Mojolicious 9.49.
|
|
73
|
+
|
|
74
|
+
Classes
|
|
75
|
+
-------
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
import Pyjo.Base
|
|
79
|
+
import Pyjo.File
|
|
80
|
+
import Pyjo.Loader
|
|
81
|
+
import Pyjo.Server
|
|
82
|
+
import Pyjo.Template
|
|
83
|
+
import Pyjo.Util
|
|
84
|
+
|
|
85
|
+
import os
|
|
86
|
+
import sys
|
|
87
|
+
import weakref
|
|
88
|
+
|
|
89
|
+
from pkgutil import extend_path
|
|
90
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
if TYPE_CHECKING:
|
|
94
|
+
import Pyjoyment
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Pyjoyment_Command(Pyjo.Base.object):
|
|
98
|
+
"""
|
|
99
|
+
:mod:`Pyjoyment.Command` inherits all methods from :mod:`Pyjo.Base` and
|
|
100
|
+
implements the following new ones.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
description: str = 'No description'
|
|
104
|
+
"""::
|
|
105
|
+
|
|
106
|
+
description = command.description
|
|
107
|
+
command.description = 'Foo'
|
|
108
|
+
|
|
109
|
+
Short description of command, used for the command list.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
quiet: bool | None = None
|
|
113
|
+
"""::
|
|
114
|
+
|
|
115
|
+
boolean = command.quiet
|
|
116
|
+
command.quiet = boolean
|
|
117
|
+
|
|
118
|
+
Limited command output.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
usage: str = 'Usage: APPLICATION\n'
|
|
122
|
+
"""::
|
|
123
|
+
|
|
124
|
+
usage = command.usage
|
|
125
|
+
command.usage = 'Foo'
|
|
126
|
+
|
|
127
|
+
Usage information for command, used for the help screen.
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
131
|
+
self._app: weakref.ref[Pyjoyment.object] | None = None
|
|
132
|
+
self._app_ref: Pyjoyment.object | None = None
|
|
133
|
+
self.template: dict[str, Any] = {'vars': True}
|
|
134
|
+
"""::
|
|
135
|
+
|
|
136
|
+
template = command.template
|
|
137
|
+
command.template = {'vars': True}
|
|
138
|
+
|
|
139
|
+
Attribute values passed to :mod:`Pyjo.Template` objects used to
|
|
140
|
+
render templates with :meth:`render_data`, defaults to activating
|
|
141
|
+
``vars``.
|
|
142
|
+
"""
|
|
143
|
+
for name, value in kwargs.items():
|
|
144
|
+
setattr(self, name, value)
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def app(self) -> 'Pyjoyment.object':
|
|
148
|
+
"""::
|
|
149
|
+
|
|
150
|
+
app = command.app
|
|
151
|
+
command.app = Pyjoyment.new()
|
|
152
|
+
|
|
153
|
+
Application for command, defaults to a :mod:`Pyjoyment.HelloWorld`
|
|
154
|
+
object. Note that this attribute is weakened. ::
|
|
155
|
+
|
|
156
|
+
# Introspect
|
|
157
|
+
for path in command.app.renderer.paths:
|
|
158
|
+
print(f'Template path: {path}')
|
|
159
|
+
"""
|
|
160
|
+
if self._app is not None:
|
|
161
|
+
if (app := self._app()) is None:
|
|
162
|
+
raise ReferenceError('weakly-referenced object no longer exists')
|
|
163
|
+
return app
|
|
164
|
+
if self._app_ref is None:
|
|
165
|
+
self._app_ref = Pyjo.Server.new().build_app('Pyjoyment.HelloWorld') # pyright: ignore[reportAttributeAccessIssue]
|
|
166
|
+
return self._app_ref # pyright: ignore[reportReturnType]
|
|
167
|
+
|
|
168
|
+
@app.setter
|
|
169
|
+
def app(self, value: 'Pyjoyment.object') -> None:
|
|
170
|
+
self._app = weakref.ref(value)
|
|
171
|
+
|
|
172
|
+
def chmod_file(self, path: str | os.PathLike[str], mode: int) -> Self:
|
|
173
|
+
"""::
|
|
174
|
+
|
|
175
|
+
command = command.chmod_file('/home/sri/foo.txt', 0o644)
|
|
176
|
+
|
|
177
|
+
Change mode of a file.
|
|
178
|
+
"""
|
|
179
|
+
Pyjo.File.path(path).chmod(mode)
|
|
180
|
+
return self._loud(f' [chmod] {path} {mode:o}')
|
|
181
|
+
|
|
182
|
+
def chmod_rel_file(self, path: str, mode: int) -> Self:
|
|
183
|
+
"""::
|
|
184
|
+
|
|
185
|
+
command = command.chmod_rel_file('foo/foo.txt', 0o644)
|
|
186
|
+
|
|
187
|
+
Portably change mode of a file relative to the current working
|
|
188
|
+
directory.
|
|
189
|
+
"""
|
|
190
|
+
return self.chmod_file(self.rel_file(path), mode)
|
|
191
|
+
|
|
192
|
+
def create_dir(self, path: str | os.PathLike[str]) -> Self:
|
|
193
|
+
"""::
|
|
194
|
+
|
|
195
|
+
command = command.create_dir('/home/sri/foo/bar')
|
|
196
|
+
|
|
197
|
+
Create a directory if it does not exist already.
|
|
198
|
+
"""
|
|
199
|
+
if os.path.isdir(path):
|
|
200
|
+
return self._loud(f' [exist] {path}')
|
|
201
|
+
Pyjo.File.path(path).make_path()
|
|
202
|
+
return self._loud(f' [mkdir] {path}')
|
|
203
|
+
|
|
204
|
+
def create_rel_dir(self, path: str) -> Self:
|
|
205
|
+
"""::
|
|
206
|
+
|
|
207
|
+
command = command.create_rel_dir('foo/bar/baz')
|
|
208
|
+
|
|
209
|
+
Portably create a directory relative to the current working directory
|
|
210
|
+
if it does not exist already.
|
|
211
|
+
"""
|
|
212
|
+
return self.create_dir(self.rel_file(path))
|
|
213
|
+
|
|
214
|
+
def extract_usage(self) -> str:
|
|
215
|
+
"""::
|
|
216
|
+
|
|
217
|
+
usage = command.extract_usage()
|
|
218
|
+
|
|
219
|
+
Extract usage message from the synopsis of the docstring of the file
|
|
220
|
+
this method was called from with :func:`Pyjo.Util.extract_usage`.
|
|
221
|
+
"""
|
|
222
|
+
return Pyjo.Util.extract_usage(sys._getframe(1).f_code.co_filename) # pyright: ignore[reportPrivateUsage]
|
|
223
|
+
|
|
224
|
+
def help(self, *args: str) -> None:
|
|
225
|
+
"""::
|
|
226
|
+
|
|
227
|
+
command.help()
|
|
228
|
+
|
|
229
|
+
Print usage information for command.
|
|
230
|
+
"""
|
|
231
|
+
print(self.usage, end='')
|
|
232
|
+
|
|
233
|
+
def rel_file(self, path: str) -> Pyjo.File.object:
|
|
234
|
+
"""::
|
|
235
|
+
|
|
236
|
+
path = command.rel_file('foo/bar.txt')
|
|
237
|
+
|
|
238
|
+
Return a :mod:`Pyjo.File` object relative to the current working
|
|
239
|
+
directory.
|
|
240
|
+
"""
|
|
241
|
+
return Pyjo.File.path().child(*path.split('/'))
|
|
242
|
+
|
|
243
|
+
def render_data(self, name: str, *args: Any) -> str:
|
|
244
|
+
"""::
|
|
245
|
+
|
|
246
|
+
data = command.render_data('foo_bar')
|
|
247
|
+
data = command.render_data('foo_bar', *args)
|
|
248
|
+
data = command.render_data('foo_bar', {'foo': 'bar'})
|
|
249
|
+
|
|
250
|
+
Render a template from the ``DATA`` section of the module of the
|
|
251
|
+
command with :mod:`Pyjo.Loader` and :mod:`Pyjo.Template`. The template
|
|
252
|
+
can be configured with :attr:`template`.
|
|
253
|
+
"""
|
|
254
|
+
template = Pyjo.Template.new(**self.template)
|
|
255
|
+
template.name = f'template {name} from DATA section'
|
|
256
|
+
output = template.render(str(Pyjo.Loader.data_section(type(self), name)), *args)
|
|
257
|
+
if isinstance(output, Exception):
|
|
258
|
+
raise output
|
|
259
|
+
return str(output)
|
|
260
|
+
|
|
261
|
+
def render_to_file(self, data: str, path: str | os.PathLike[str], *args: Any) -> Self:
|
|
262
|
+
"""::
|
|
263
|
+
|
|
264
|
+
command = command.render_to_file('foo_bar', '/home/sri/foo.txt')
|
|
265
|
+
command = command.render_to_file('foo_bar', '/home/sri/foo.txt', *args)
|
|
266
|
+
command = command.render_to_file('foo_bar', '/home/sri/foo.txt', {'foo': 'bar'})
|
|
267
|
+
|
|
268
|
+
Render a template with :meth:`render_data` to a file if it does not
|
|
269
|
+
exist already, and create the directory if necessary.
|
|
270
|
+
"""
|
|
271
|
+
return self.write_file(path, self.render_data(data, *args))
|
|
272
|
+
|
|
273
|
+
def render_to_rel_file(self, data: str, path: str, *args: Any) -> Self:
|
|
274
|
+
"""::
|
|
275
|
+
|
|
276
|
+
command = command.render_to_rel_file('foo_bar', 'foo/bar.txt')
|
|
277
|
+
command = command.render_to_rel_file('foo_bar', 'foo/bar.txt', *args)
|
|
278
|
+
command = command.render_to_rel_file('foo_bar', 'foo/bar.txt', {'foo': 'bar'})
|
|
279
|
+
|
|
280
|
+
Portably render a template with :meth:`render_data` to a file relative
|
|
281
|
+
to the current working directory if it does not exist already, and
|
|
282
|
+
create the directory if necessary.
|
|
283
|
+
"""
|
|
284
|
+
return self.render_to_file(data, self.rel_file(path), *args)
|
|
285
|
+
|
|
286
|
+
def run(self, *args: str) -> Any:
|
|
287
|
+
"""::
|
|
288
|
+
|
|
289
|
+
command.run()
|
|
290
|
+
command.run(*sys.argv[1:])
|
|
291
|
+
|
|
292
|
+
Run command. Meant to be overloaded in a subclass.
|
|
293
|
+
"""
|
|
294
|
+
raise NotImplementedError('Method "run" not implemented by subclass')
|
|
295
|
+
|
|
296
|
+
def write_file(self, path: str | os.PathLike[str], data: str | bytes) -> Self:
|
|
297
|
+
"""::
|
|
298
|
+
|
|
299
|
+
command = command.write_file('/home/sri/foo.txt', 'Hello World!')
|
|
300
|
+
|
|
301
|
+
Write text to a file if it does not exist already, and create the
|
|
302
|
+
directory if necessary.
|
|
303
|
+
"""
|
|
304
|
+
if os.path.isfile(path):
|
|
305
|
+
return self._loud(f' [exist] {path}')
|
|
306
|
+
self.create_dir(Pyjo.File.path(path).dirname())
|
|
307
|
+
Pyjo.File.path(path).spew(data)
|
|
308
|
+
return self._loud(f' [write] {path}')
|
|
309
|
+
|
|
310
|
+
def write_rel_file(self, path: str, data: str | bytes) -> Self:
|
|
311
|
+
"""::
|
|
312
|
+
|
|
313
|
+
command = command.write_rel_file('foo/bar.txt', 'Hello World!')
|
|
314
|
+
|
|
315
|
+
Portably write text to a file relative to the current working
|
|
316
|
+
directory if it does not exist already, and create the directory if
|
|
317
|
+
necessary.
|
|
318
|
+
"""
|
|
319
|
+
return self.write_file(self.rel_file(path), data)
|
|
320
|
+
|
|
321
|
+
def _loud(self, msg: str) -> Self:
|
|
322
|
+
if not self.quiet:
|
|
323
|
+
print(msg)
|
|
324
|
+
return self
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
# Not in Mojolicious: a namespace that other distributions can add commands to
|
|
328
|
+
__path__ = extend_path(__path__, __name__)
|
|
329
|
+
|
|
330
|
+
new = Pyjoyment_Command.new
|
|
331
|
+
object = Pyjoyment_Command
|
|
332
|
+
Command = Pyjoyment_Command
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjoyment.Command.asgi - ASGI command
|
|
3
|
+
=====================================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
Usage: APPLICATION asgi [OPTIONS]
|
|
7
|
+
|
|
8
|
+
application = app.start('asgi')
|
|
9
|
+
PYJO_ASGI=1 uvicorn myapp:application
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
-h, --help Show this summary of available options
|
|
13
|
+
--home <path> Path to home directory of your application,
|
|
14
|
+
defaults to the value of PYJO_HOME or
|
|
15
|
+
auto-detection
|
|
16
|
+
--log-format <name> Format of log messages, "text" or "json",
|
|
17
|
+
defaults to the value of PYJO_LOG_FORMAT or
|
|
18
|
+
"text"
|
|
19
|
+
-m, --mode <name> Operating mode for your application, defaults to
|
|
20
|
+
the value of PYJO_MODE or "development"
|
|
21
|
+
|
|
22
|
+
:mod:`Pyjoyment.Command.asgi` starts applications with the
|
|
23
|
+
:mod:`Pyjo.Server.ASGI` backend: it returns the ASGI application, which a
|
|
24
|
+
script keeps for the ASGI server that imports it. The script of an application
|
|
25
|
+
that ends with ``application = app.start()`` runs this command when the
|
|
26
|
+
``PYJO_ASGI`` environment variable is set, and the command of its arguments
|
|
27
|
+
otherwise.
|
|
28
|
+
|
|
29
|
+
This is a core command, that means it is always enabled and its code a good
|
|
30
|
+
example for learning to build new commands, you're welcome to fork it.
|
|
31
|
+
|
|
32
|
+
See :mod:`Pyjoyment.Commands` for a list of commands that are available by
|
|
33
|
+
default.
|
|
34
|
+
|
|
35
|
+
See also
|
|
36
|
+
--------
|
|
37
|
+
|
|
38
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
39
|
+
|
|
40
|
+
Inspired by `Mojolicious::Command::psgi
|
|
41
|
+
<https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojolicious/Command/psgi.pm>`_ of Mojolicious 9.49, for ASGI.
|
|
42
|
+
|
|
43
|
+
Classes
|
|
44
|
+
-------
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
# Not in Mojolicious: the command of ASGI, as Pyjoyment.Command.wsgi of WSGI
|
|
48
|
+
|
|
49
|
+
import Pyjo.Server.ASGI
|
|
50
|
+
import Pyjoyment.Command
|
|
51
|
+
|
|
52
|
+
from Pyjo.Util import extract_usage
|
|
53
|
+
|
|
54
|
+
from typing import Any
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Pyjoyment_Command_asgi(Pyjoyment.Command.object):
|
|
58
|
+
"""
|
|
59
|
+
:mod:`Pyjoyment.Command.asgi` inherits all attributes and methods from
|
|
60
|
+
:mod:`Pyjoyment.Command` and implements the following new ones.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
description = 'Start application with ASGI'
|
|
64
|
+
"""::
|
|
65
|
+
|
|
66
|
+
description = asgi.description
|
|
67
|
+
asgi.description = 'Foo'
|
|
68
|
+
|
|
69
|
+
Short description of this command, used for the command list.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
usage = extract_usage()
|
|
73
|
+
"""::
|
|
74
|
+
|
|
75
|
+
usage = asgi.usage
|
|
76
|
+
asgi.usage = 'Foo'
|
|
77
|
+
|
|
78
|
+
Usage information for this command, used for the help screen.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def run(self, *args: str) -> Any:
|
|
82
|
+
"""::
|
|
83
|
+
|
|
84
|
+
application = asgi.run()
|
|
85
|
+
|
|
86
|
+
Run this command.
|
|
87
|
+
"""
|
|
88
|
+
return Pyjo.Server.ASGI.new(app=self.app).to_asgi_app()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
new = Pyjoyment_Command_asgi.new
|
|
92
|
+
object = Pyjoyment_Command_asgi
|
Pyjoyment/Command/cgi.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjoyment.Command.cgi - CGI command
|
|
3
|
+
===================================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
Usage: APPLICATION cgi [OPTIONS]
|
|
7
|
+
|
|
8
|
+
./myapp.py cgi
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
-h, --help Show this summary of available options
|
|
12
|
+
--home <path> Path to home directory of your application,
|
|
13
|
+
defaults to the value of PYJO_HOME or
|
|
14
|
+
auto-detection
|
|
15
|
+
--log-format <name> Format of log messages, "text" or "json",
|
|
16
|
+
defaults to the value of PYJO_LOG_FORMAT or
|
|
17
|
+
"text"
|
|
18
|
+
-m, --mode <name> Operating mode for your application, defaults to
|
|
19
|
+
the value of PYJO_MODE or "development"
|
|
20
|
+
--nph Enable non-parsed-header mode
|
|
21
|
+
|
|
22
|
+
:mod:`Pyjoyment.Command.cgi` starts applications with the
|
|
23
|
+
:mod:`Pyjo.Server.CGI` backend.
|
|
24
|
+
|
|
25
|
+
This is a core command, that means it is always enabled and its code a good
|
|
26
|
+
example for learning to build new commands, you're welcome to fork it.
|
|
27
|
+
|
|
28
|
+
See :mod:`Pyjoyment.Commands` for a list of commands that are available by
|
|
29
|
+
default.
|
|
30
|
+
|
|
31
|
+
See also
|
|
32
|
+
--------
|
|
33
|
+
|
|
34
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
35
|
+
|
|
36
|
+
Ported from `Mojolicious::Command::cgi
|
|
37
|
+
<https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojolicious/Command/cgi.pm>`_ of Mojolicious 9.49.
|
|
38
|
+
|
|
39
|
+
Classes
|
|
40
|
+
-------
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
import Pyjo.Exception
|
|
44
|
+
import Pyjo.Server.CGI
|
|
45
|
+
import Pyjoyment.Command
|
|
46
|
+
|
|
47
|
+
from Pyjo.Util import extract_usage, getopt
|
|
48
|
+
|
|
49
|
+
from typing import Any
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Pyjoyment_Command_cgi(Pyjoyment.Command.object):
|
|
53
|
+
"""
|
|
54
|
+
:mod:`Pyjoyment.Command.cgi` inherits all attributes and methods from
|
|
55
|
+
:mod:`Pyjoyment.Command` and implements the following new ones.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
description = 'Start application with CGI'
|
|
59
|
+
"""::
|
|
60
|
+
|
|
61
|
+
description = cgi.description
|
|
62
|
+
cgi.description = 'Foo'
|
|
63
|
+
|
|
64
|
+
Short description of this command, used for the command list.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
usage = extract_usage()
|
|
68
|
+
"""::
|
|
69
|
+
|
|
70
|
+
usage = cgi.usage
|
|
71
|
+
cgi.usage = 'Foo'
|
|
72
|
+
|
|
73
|
+
Usage information for this command, used for the help screen.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def run(self, *args: str) -> Any:
|
|
77
|
+
"""::
|
|
78
|
+
|
|
79
|
+
cgi.run(*sys.argv[1:])
|
|
80
|
+
|
|
81
|
+
Run this command.
|
|
82
|
+
"""
|
|
83
|
+
arguments = list(args)
|
|
84
|
+
if not (opts := getopt(arguments, {'nph': None})):
|
|
85
|
+
raise Pyjo.Exception.new(self.usage)
|
|
86
|
+
return Pyjo.Server.CGI.new(app=self.app, nph=bool(opts.nph)).run()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
new = Pyjoyment_Command_cgi.new
|
|
90
|
+
object = Pyjoyment_Command_cgi
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjoyment.Command.daemon - Daemon command
|
|
3
|
+
=========================================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
Usage: APPLICATION daemon [OPTIONS]
|
|
7
|
+
|
|
8
|
+
./myapp.py daemon
|
|
9
|
+
./myapp.py daemon -m production -p -l http://*:8080
|
|
10
|
+
./myapp.py daemon -l http://127.0.0.1:8080 -l https://[::]:8081
|
|
11
|
+
./myapp.py daemon -l 'https://*:443?cert=./server.crt&key=./server.key'
|
|
12
|
+
./myapp.py daemon -l http+unix://%2Ftmp%2Fmyapp.sock
|
|
13
|
+
./myapp.py daemon -l fcgi://127.0.0.1:9000
|
|
14
|
+
./myapp.py daemon -l http://127.0.0.1:8080 -p 127.0.0.0/8 -p fc00::/7
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
-b, --backlog <size> Listen backlog size, defaults to
|
|
18
|
+
SOMAXCONN
|
|
19
|
+
-c, --clients <number> Maximum number of concurrent
|
|
20
|
+
connections, defaults to 1000
|
|
21
|
+
-h, --help Show this summary of available options
|
|
22
|
+
--home <path> Path to home directory of your
|
|
23
|
+
application, defaults to the value of
|
|
24
|
+
PYJO_HOME or auto-detection
|
|
25
|
+
-i, --inactivity-timeout <seconds> Inactivity timeout, defaults to the
|
|
26
|
+
value of PYJO_INACTIVITY_TIMEOUT or 30
|
|
27
|
+
-k, --keep-alive-timeout <seconds> Keep-alive timeout, defaults to the
|
|
28
|
+
value of PYJO_KEEP_ALIVE_TIMEOUT or 5
|
|
29
|
+
-l, --listen <location> One or more locations you want to
|
|
30
|
+
listen on, defaults to the value of
|
|
31
|
+
PYJO_LISTEN, the port of PORT or
|
|
32
|
+
"http://*:3000"
|
|
33
|
+
--log-format <name> Format of log messages, "text" or
|
|
34
|
+
"json", defaults to the value of
|
|
35
|
+
PYJO_LOG_FORMAT or "text"
|
|
36
|
+
-m, --mode <name> Operating mode for your application,
|
|
37
|
+
defaults to the value of PYJO_MODE or
|
|
38
|
+
"development"
|
|
39
|
+
-p, --proxy [<network>] Activate reverse proxy support,
|
|
40
|
+
defaults to the value of
|
|
41
|
+
PYJO_REVERSE_PROXY, optionally takes
|
|
42
|
+
one or more trusted proxy addresses or
|
|
43
|
+
networks
|
|
44
|
+
-r, --requests <number> Maximum number of requests per
|
|
45
|
+
keep-alive connection, defaults to 100
|
|
46
|
+
-S, --shutdown-delay <seconds> Time to keep serving after INT or TERM
|
|
47
|
+
before shutting down gracefully,
|
|
48
|
+
defaults to 0
|
|
49
|
+
|
|
50
|
+
:mod:`Pyjoyment.Command.daemon` starts applications with the
|
|
51
|
+
:mod:`Pyjo.Server.Daemon` backend.
|
|
52
|
+
|
|
53
|
+
An option that is not given has the value of the environment variable of
|
|
54
|
+
``PYJO_`` and its name, as ``PYJO_CLIENTS`` for ``--clients``, with the
|
|
55
|
+
values of ``--listen`` and ``--proxy`` separated by commas, see
|
|
56
|
+
:mod:`Pyjo.GetOpt`, so that the environment of a container or a platform
|
|
57
|
+
can tune the server. ::
|
|
58
|
+
|
|
59
|
+
PYJO_CLIENTS=100 ./myapp.py daemon
|
|
60
|
+
|
|
61
|
+
This is a core command, that means it is always enabled and its code a good
|
|
62
|
+
example for learning to build new commands, you're welcome to fork it.
|
|
63
|
+
|
|
64
|
+
See :mod:`Pyjoyment.Commands` for a list of commands that are available by
|
|
65
|
+
default.
|
|
66
|
+
|
|
67
|
+
See also
|
|
68
|
+
--------
|
|
69
|
+
|
|
70
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
71
|
+
|
|
72
|
+
Ported from `Mojolicious::Command::daemon
|
|
73
|
+
<https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojolicious/Command/daemon.pm>`_ of Mojolicious 9.49.
|
|
74
|
+
|
|
75
|
+
Classes
|
|
76
|
+
-------
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
import Pyjo.Exception
|
|
80
|
+
import Pyjo.Server.Daemon
|
|
81
|
+
import Pyjoyment.Command
|
|
82
|
+
|
|
83
|
+
from Pyjo.Util import extract_usage, getopt
|
|
84
|
+
|
|
85
|
+
from typing import Any
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class Pyjoyment_Command_daemon(Pyjoyment.Command.object):
|
|
89
|
+
"""
|
|
90
|
+
:mod:`Pyjoyment.Command.daemon` inherits all attributes and methods from
|
|
91
|
+
:mod:`Pyjoyment.Command` and implements the following new ones.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
description = 'Start application with HTTP and WebSocket server'
|
|
95
|
+
"""::
|
|
96
|
+
|
|
97
|
+
description = daemon.description
|
|
98
|
+
daemon.description = 'Foo'
|
|
99
|
+
|
|
100
|
+
Short description of this command, used for the command list.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
usage = extract_usage()
|
|
104
|
+
"""::
|
|
105
|
+
|
|
106
|
+
usage = daemon.usage
|
|
107
|
+
daemon.usage = 'Foo'
|
|
108
|
+
|
|
109
|
+
Usage information for this command, used for the help screen.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
def build_server(self, *args: str) -> Pyjo.Server.Daemon.object:
|
|
113
|
+
"""::
|
|
114
|
+
|
|
115
|
+
server = daemon.build_server(*sys.argv[1:])
|
|
116
|
+
|
|
117
|
+
Build :mod:`Pyjo.Server.Daemon` instance from command line arguments.
|
|
118
|
+
"""
|
|
119
|
+
arguments = list(args)
|
|
120
|
+
daemon = Pyjo.Server.Daemon.new(app=self.app)
|
|
121
|
+
listen: list[str] = []
|
|
122
|
+
proxy: list[str] = []
|
|
123
|
+
# Not in Mojolicious: the options from the environment variables of their names
|
|
124
|
+
if not getopt(
|
|
125
|
+
arguments,
|
|
126
|
+
{
|
|
127
|
+
'b|backlog=i': lambda name, value: setattr(daemon, 'backlog', value),
|
|
128
|
+
'c|clients=i': lambda name, value: setattr(daemon, 'max_clients', value),
|
|
129
|
+
'i|inactivity-timeout=i': lambda name, value: setattr(daemon, 'inactivity_timeout', value),
|
|
130
|
+
'k|keep-alive-timeout=i': lambda name, value: setattr(daemon, 'keep_alive_timeout', value),
|
|
131
|
+
'l|listen=s': listen,
|
|
132
|
+
'p|proxy:s': proxy,
|
|
133
|
+
'r|requests=i': lambda name, value: setattr(daemon, 'max_requests', value),
|
|
134
|
+
# Not in Mojolicious: the delay of the graceful shutdown, while the readiness fails
|
|
135
|
+
'S|shutdown-delay=i': lambda name, value: setattr(daemon, 'shutdown_delay', value),
|
|
136
|
+
},
|
|
137
|
+
env_prefix='PYJO_',
|
|
138
|
+
):
|
|
139
|
+
raise Pyjo.Exception.new(self.usage)
|
|
140
|
+
|
|
141
|
+
if listen:
|
|
142
|
+
daemon.listen = listen
|
|
143
|
+
if proxy:
|
|
144
|
+
daemon.reverse_proxy = True
|
|
145
|
+
if trusted := [p for p in proxy if p]:
|
|
146
|
+
daemon.trusted_proxies = trusted
|
|
147
|
+
return daemon
|
|
148
|
+
|
|
149
|
+
def run(self, *args: str) -> Any:
|
|
150
|
+
"""::
|
|
151
|
+
|
|
152
|
+
daemon.run(*sys.argv[1:])
|
|
153
|
+
|
|
154
|
+
Run this command.
|
|
155
|
+
"""
|
|
156
|
+
return self.build_server(*args).run()
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
new = Pyjoyment_Command_daemon.new
|
|
160
|
+
object = Pyjoyment_Command_daemon
|