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
Pyjo/__init__.py
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjo - Web development toolkit
|
|
3
|
+
==============================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
# HTTP/WebSocket user agent
|
|
7
|
+
import Pyjo.UserAgent
|
|
8
|
+
ua = Pyjo.UserAgent.new()
|
|
9
|
+
print(ua.get('www.mojolicious.org').result.headers.server)
|
|
10
|
+
|
|
11
|
+
# HTML/XML DOM parser with CSS selectors
|
|
12
|
+
import Pyjo.DOM
|
|
13
|
+
dom = Pyjo.DOM.new('<div><b>Hello Pyjo!</b></div>')
|
|
14
|
+
print(dom.at('div > b').text)
|
|
15
|
+
|
|
16
|
+
# Python-ish templates
|
|
17
|
+
import Pyjo.Template
|
|
18
|
+
mt = Pyjo.Template.new(vars=True)
|
|
19
|
+
print(mt.render('Hello <%= what %>!', {'what': 'Pyjo'}))
|
|
20
|
+
|
|
21
|
+
# HTTP/WebSocket server
|
|
22
|
+
import Pyjo.Server.Daemon
|
|
23
|
+
daemon = Pyjo.Server.Daemon.new(listen=['http://*:8080'])
|
|
24
|
+
|
|
25
|
+
@daemon.unsubscribe('request').on('request')
|
|
26
|
+
def request(daemon, tx):
|
|
27
|
+
tx.res.code = 200
|
|
28
|
+
tx.res.body = b'Hello Pyjo!'
|
|
29
|
+
tx.resume()
|
|
30
|
+
|
|
31
|
+
daemon.run()
|
|
32
|
+
|
|
33
|
+
# Event loop
|
|
34
|
+
import Pyjo.IOLoop
|
|
35
|
+
for seconds in range(1, 6):
|
|
36
|
+
Pyjo.IOLoop.timer(seconds, lambda loop, seconds=seconds: print(seconds))
|
|
37
|
+
Pyjo.IOLoop.start()
|
|
38
|
+
|
|
39
|
+
A powerful web development toolkit, with all the basic tools and helpers
|
|
40
|
+
needed to write simple web applications and higher level web frameworks, such
|
|
41
|
+
as :mod:`Pyjoyment`. Some of the most commonly used tools are
|
|
42
|
+
:mod:`Pyjo.UserAgent`, :mod:`Pyjo.DOM`, :mod:`Pyjo.JSON`,
|
|
43
|
+
:mod:`Pyjo.Server.Daemon`, :mod:`Pyjo.Server.Prefork`, :mod:`Pyjo.IOLoop` and
|
|
44
|
+
:mod:`Pyjo.Template`.
|
|
45
|
+
|
|
46
|
+
One-liners
|
|
47
|
+
----------
|
|
48
|
+
::
|
|
49
|
+
|
|
50
|
+
$ python -m Pyjo 'g("mojolicious.org").dom().at("title").text'
|
|
51
|
+
|
|
52
|
+
A collection of functions for fun Python one-liners, which
|
|
53
|
+
``from Pyjo import *`` imports, and with which ``python -m Pyjo`` runs its
|
|
54
|
+
code: the value of an expression is printed, and the arguments after the code
|
|
55
|
+
are in :data:`sys.argv`. Ten redirects will be followed by default, you can
|
|
56
|
+
change this behavior with the ``PYJO_MAX_REDIRECTS`` environment variable. ::
|
|
57
|
+
|
|
58
|
+
$ PYJO_MAX_REDIRECTS=0 python -m Pyjo 'g("example.com").code'
|
|
59
|
+
|
|
60
|
+
Proxy detection is enabled by default, but you can disable it with the
|
|
61
|
+
``PYJO_PROXY`` environment variable. ::
|
|
62
|
+
|
|
63
|
+
$ PYJO_PROXY=0 python -m Pyjo 'g("example.com").body'
|
|
64
|
+
|
|
65
|
+
TLS certificate verification can be disabled with the ``PYJO_INSECURE``
|
|
66
|
+
environment variable. ::
|
|
67
|
+
|
|
68
|
+
$ PYJO_INSECURE=1 python -m Pyjo 'g("https://127.0.0.1:3000").body'
|
|
69
|
+
|
|
70
|
+
If it is not already defined, ``python -m Pyjo`` will set the
|
|
71
|
+
``PYJO_LOG_LEVEL`` environment variable to ``fatal``.
|
|
72
|
+
|
|
73
|
+
:mod:`Pyjo` is a namespace package that may be split across multiple
|
|
74
|
+
distributions, as another reactor in :mod:`Pyjo.Reactor` comes from one of its
|
|
75
|
+
own.
|
|
76
|
+
|
|
77
|
+
See also
|
|
78
|
+
--------
|
|
79
|
+
|
|
80
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
81
|
+
|
|
82
|
+
Ported from `Mojo <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojo.pm>`_
|
|
83
|
+
and `ojo <https://github.com/mojolicious/mojo/blob/v9.49/lib/ojo.pm>`_ of
|
|
84
|
+
Mojolicious 9.49.
|
|
85
|
+
|
|
86
|
+
Functions
|
|
87
|
+
---------
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
import os
|
|
91
|
+
import sys
|
|
92
|
+
import time
|
|
93
|
+
|
|
94
|
+
from collections.abc import Callable
|
|
95
|
+
from pkgutil import extend_path
|
|
96
|
+
from typing import TYPE_CHECKING, Any
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
if TYPE_CHECKING:
|
|
100
|
+
import Pyjo.Collection
|
|
101
|
+
import Pyjo.DOM
|
|
102
|
+
import Pyjo.File
|
|
103
|
+
import Pyjo.JSON.Schema
|
|
104
|
+
import Pyjo.Message.Response
|
|
105
|
+
import Pyjo.String.Bytes
|
|
106
|
+
import Pyjo.String.Unicode
|
|
107
|
+
import Pyjo.URL
|
|
108
|
+
import Pyjo.UserAgent
|
|
109
|
+
|
|
110
|
+
import re
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# Not in Mojolicious: a namespace package, as Python does not merge a regular package from every directory of sys.path
|
|
114
|
+
__path__ = extend_path(__path__, __name__)
|
|
115
|
+
|
|
116
|
+
# The functions of ojo, which the modules they use are imported for when they are called, so that a module of Pyjo
|
|
117
|
+
# does not import them
|
|
118
|
+
__all__ = ['a', 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'l', 'n', 'o', 'p', 'q', 'r', 't', 'u', 'w', 'x', 'z']
|
|
119
|
+
|
|
120
|
+
_agent: 'Pyjo.UserAgent.object | None' = None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# Unlike Mojolicious: the user agent of the functions is one of their own, whose server gets the application of
|
|
124
|
+
# Pyjoyment.Lite when a makes it, where ojo makes the application for the package that uses it and takes its user agent,
|
|
125
|
+
# as a module of Pyjo imports Pyjoyment only when a function needs it
|
|
126
|
+
# Left out from Mojolicious: the hook around_action that sets $_ to the controller, as an action gets it as its argument
|
|
127
|
+
def _ua() -> 'Pyjo.UserAgent.object':
|
|
128
|
+
global _agent
|
|
129
|
+
if _agent is None:
|
|
130
|
+
import Pyjo.UserAgent
|
|
131
|
+
|
|
132
|
+
_agent = Pyjo.UserAgent.new()
|
|
133
|
+
if os.environ.get('PYJO_MAX_REDIRECTS') is None:
|
|
134
|
+
_agent.max_redirects = 10
|
|
135
|
+
if os.environ.get('PYJO_PROXY') is None:
|
|
136
|
+
_agent.proxy.detect()
|
|
137
|
+
return _agent
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def a(*args: Any, **constraints: Any) -> Any:
|
|
141
|
+
"""::
|
|
142
|
+
|
|
143
|
+
app = a('/hello', lambda c: c.render(json={'hello': 'world'}))
|
|
144
|
+
|
|
145
|
+
Create a route with ``any`` of :mod:`Pyjoyment.Lite` and return the
|
|
146
|
+
current :mod:`Pyjoyment.Lite` object, the application of the module that
|
|
147
|
+
calls it. ::
|
|
148
|
+
|
|
149
|
+
$ python -m Pyjo 'a("/hello", {"text": "Hello Pyjo!"}).start()' daemon
|
|
150
|
+
"""
|
|
151
|
+
import Pyjoyment.Lite
|
|
152
|
+
|
|
153
|
+
functions = Pyjoyment.Lite._functions(sys._getframe(1)) # pyright: ignore[reportPrivateUsage]
|
|
154
|
+
ua = _ua()
|
|
155
|
+
ua.server.app = functions['app']
|
|
156
|
+
functions['any'](*args, **constraints)
|
|
157
|
+
return ua.server.app
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def b(*parts: object) -> 'Pyjo.String.Bytes.object':
|
|
161
|
+
"""::
|
|
162
|
+
|
|
163
|
+
stream = b(b'lalala')
|
|
164
|
+
|
|
165
|
+
Turn bytes into a :mod:`Pyjo.String.Bytes` object. ::
|
|
166
|
+
|
|
167
|
+
$ python -m Pyjo 'b(g("mojolicious.org").body).html_unescape().say()'
|
|
168
|
+
"""
|
|
169
|
+
import Pyjo.String.Bytes
|
|
170
|
+
|
|
171
|
+
return Pyjo.String.Bytes.b(*parts)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def c[T](*elements: T) -> 'Pyjo.Collection.object[T]':
|
|
175
|
+
"""::
|
|
176
|
+
|
|
177
|
+
collection = c(1, 2, 3)
|
|
178
|
+
|
|
179
|
+
Turn list into a :mod:`Pyjo.Collection` object.
|
|
180
|
+
"""
|
|
181
|
+
import Pyjo.Collection
|
|
182
|
+
|
|
183
|
+
return Pyjo.Collection.c(*elements)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def d(*args: Any, **kwargs: Any) -> 'Pyjo.Message.Response.object':
|
|
187
|
+
"""::
|
|
188
|
+
|
|
189
|
+
res = d('example.com')
|
|
190
|
+
res = d('http://example.com', {'Accept': '*/*'}, b'Hi!')
|
|
191
|
+
res = d('http://example.com', {'Accept': '*/*'}, form={'a': 'b'})
|
|
192
|
+
res = d('http://example.com', {'Accept': '*/*'}, json={'a': 'b'})
|
|
193
|
+
|
|
194
|
+
Perform ``DELETE`` request with :attr:`Pyjo.UserAgent.Pyjo_UserAgent.delete`
|
|
195
|
+
and return resulting :mod:`Pyjo.Message.Response` object.
|
|
196
|
+
"""
|
|
197
|
+
return _ua().delete(*args, **kwargs).result
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def f(*parts: object) -> 'Pyjo.File.object':
|
|
201
|
+
"""::
|
|
202
|
+
|
|
203
|
+
path = f('/home/sri/foo.txt')
|
|
204
|
+
|
|
205
|
+
Turn string into a :mod:`Pyjo.File` object. ::
|
|
206
|
+
|
|
207
|
+
$ python -m Pyjo 'r(j(f("hello.json").slurp()))'
|
|
208
|
+
"""
|
|
209
|
+
import Pyjo.File
|
|
210
|
+
|
|
211
|
+
return Pyjo.File.path(*parts)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def g(*args: Any, **kwargs: Any) -> 'Pyjo.Message.Response.object':
|
|
215
|
+
"""::
|
|
216
|
+
|
|
217
|
+
res = g('example.com')
|
|
218
|
+
res = g('http://example.com', {'Accept': '*/*'}, b'Hi!')
|
|
219
|
+
res = g('http://example.com', {'Accept': '*/*'}, form={'a': 'b'})
|
|
220
|
+
res = g('http://example.com', {'Accept': '*/*'}, json={'a': 'b'})
|
|
221
|
+
|
|
222
|
+
Perform ``GET`` request with :attr:`Pyjo.UserAgent.Pyjo_UserAgent.get` and
|
|
223
|
+
return resulting :mod:`Pyjo.Message.Response` object. ::
|
|
224
|
+
|
|
225
|
+
$ python -m Pyjo 'g("mojolicious.org").dom("h1").map("text").join("\\n")'
|
|
226
|
+
"""
|
|
227
|
+
return _ua().get(*args, **kwargs).result
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def h(*args: Any, **kwargs: Any) -> 'Pyjo.Message.Response.object':
|
|
231
|
+
"""::
|
|
232
|
+
|
|
233
|
+
res = h('example.com')
|
|
234
|
+
res = h('http://example.com', {'Accept': '*/*'}, b'Hi!')
|
|
235
|
+
res = h('http://example.com', {'Accept': '*/*'}, form={'a': 'b'})
|
|
236
|
+
res = h('http://example.com', {'Accept': '*/*'}, json={'a': 'b'})
|
|
237
|
+
|
|
238
|
+
Perform ``HEAD`` request with :attr:`Pyjo.UserAgent.Pyjo_UserAgent.head` and
|
|
239
|
+
return resulting :mod:`Pyjo.Message.Response` object.
|
|
240
|
+
"""
|
|
241
|
+
return _ua().head(*args, **kwargs).result
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def j(value: Any) -> Any:
|
|
245
|
+
"""::
|
|
246
|
+
|
|
247
|
+
data = j([1, 2, 3])
|
|
248
|
+
data = j({'foo': 'bar'})
|
|
249
|
+
value = j(data)
|
|
250
|
+
|
|
251
|
+
Encode Python data structure or decode JSON with :func:`Pyjo.JSON.j`. ::
|
|
252
|
+
|
|
253
|
+
$ python -m Pyjo 'f("hello.json").spew(j({"hello": "world!"}))'
|
|
254
|
+
"""
|
|
255
|
+
import Pyjo.JSON
|
|
256
|
+
|
|
257
|
+
return Pyjo.JSON.j(value)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def l(*args: Any) -> 'Pyjo.URL.object': # noqa: E743
|
|
261
|
+
"""::
|
|
262
|
+
|
|
263
|
+
url = l('https://mojolicious.org')
|
|
264
|
+
|
|
265
|
+
Turn a string into a :mod:`Pyjo.URL` object. ::
|
|
266
|
+
|
|
267
|
+
$ python -m Pyjo 'l("/perldoc").to_abs(l("https://mojolicious.org"))'
|
|
268
|
+
"""
|
|
269
|
+
import Pyjo.URL
|
|
270
|
+
|
|
271
|
+
return Pyjo.URL.new(*args)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def n(cb: Callable[[], object], count: int = 1) -> None:
|
|
275
|
+
"""::
|
|
276
|
+
|
|
277
|
+
n(lambda: ...)
|
|
278
|
+
n(lambda: ..., 100)
|
|
279
|
+
|
|
280
|
+
Benchmark callback and print the results to ``sys.stderr``, with an
|
|
281
|
+
optional number of iterations, which defaults to ``1``. ::
|
|
282
|
+
|
|
283
|
+
$ python -m Pyjo 'n(lambda: print(g("mojolicious.org").code))'
|
|
284
|
+
"""
|
|
285
|
+
# Not in Mojolicious: the timing of Benchmark, which Python does not have, without the time of an empty loop
|
|
286
|
+
start, times = time.perf_counter(), os.times()
|
|
287
|
+
for _ in range(count):
|
|
288
|
+
cb()
|
|
289
|
+
wall, end = time.perf_counter() - start, os.times()
|
|
290
|
+
usr, sys_ = end.user - times.user, end.system - times.system
|
|
291
|
+
line = f'{wall:2g} wallclock secs ({usr:5.2f} usr + {sys_:5.2f} sys = {usr + sys_:5.2f} CPU)'
|
|
292
|
+
if usr + sys_ > 0:
|
|
293
|
+
line += f' @ {count / (usr + sys_):5.2f}/s (n={count})'
|
|
294
|
+
print(line, file=sys.stderr)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def o(*args: Any, **kwargs: Any) -> 'Pyjo.Message.Response.object':
|
|
298
|
+
"""::
|
|
299
|
+
|
|
300
|
+
res = o('example.com')
|
|
301
|
+
res = o('http://example.com', {'Accept': '*/*'}, b'Hi!')
|
|
302
|
+
res = o('http://example.com', {'Accept': '*/*'}, form={'a': 'b'})
|
|
303
|
+
res = o('http://example.com', {'Accept': '*/*'}, json={'a': 'b'})
|
|
304
|
+
|
|
305
|
+
Perform ``OPTIONS`` request with
|
|
306
|
+
:attr:`Pyjo.UserAgent.Pyjo_UserAgent.options` and return resulting
|
|
307
|
+
:mod:`Pyjo.Message.Response` object.
|
|
308
|
+
"""
|
|
309
|
+
return _ua().options(*args, **kwargs).result
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def p(*args: Any, **kwargs: Any) -> 'Pyjo.Message.Response.object':
|
|
313
|
+
"""::
|
|
314
|
+
|
|
315
|
+
res = p('example.com')
|
|
316
|
+
res = p('http://example.com', {'Accept': '*/*'}, b'Hi!')
|
|
317
|
+
res = p('http://example.com', {'Accept': '*/*'}, form={'a': 'b'})
|
|
318
|
+
res = p('http://example.com', {'Accept': '*/*'}, json={'a': 'b'})
|
|
319
|
+
|
|
320
|
+
Perform ``POST`` request with :attr:`Pyjo.UserAgent.Pyjo_UserAgent.post` and
|
|
321
|
+
return resulting :mod:`Pyjo.Message.Response` object.
|
|
322
|
+
"""
|
|
323
|
+
return _ua().post(*args, **kwargs).result
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# Not in Mojolicious: a regular expression, as qr// of Perl makes it, which re.compile makes long in a one-liner
|
|
327
|
+
def q(pattern: str, flags: int = 0) -> 're.Pattern[str]':
|
|
328
|
+
"""::
|
|
329
|
+
|
|
330
|
+
regex = q(r'/phpinfo\\.php')
|
|
331
|
+
regex = q(r'/php(?P<path>/.*)?')
|
|
332
|
+
|
|
333
|
+
Compile a regular expression with :func:`re.compile`, as ``qr//`` does in
|
|
334
|
+
Perl, as the whole path that :mod:`Pyjoyment.Plugin.Mount` mounts an
|
|
335
|
+
application under. ::
|
|
336
|
+
|
|
337
|
+
$ python -m Pyjo 'bool(q(r"\\d+").fullmatch("42"))'
|
|
338
|
+
"""
|
|
339
|
+
import re
|
|
340
|
+
|
|
341
|
+
return re.compile(pattern, flags)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def r(*values: object) -> str:
|
|
345
|
+
"""::
|
|
346
|
+
|
|
347
|
+
python = r({'data': 'structure'})
|
|
348
|
+
|
|
349
|
+
Dump a Python data structure with :func:`Pyjo.Util.dumper`. ::
|
|
350
|
+
|
|
351
|
+
$ python -m Pyjo 'r(g("example.com").headers.to_dict())'
|
|
352
|
+
"""
|
|
353
|
+
import Pyjo.Util
|
|
354
|
+
|
|
355
|
+
return Pyjo.Util.dumper(*values)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def t(*args: Any, **kwargs: Any) -> 'Pyjo.Message.Response.object':
|
|
359
|
+
"""::
|
|
360
|
+
|
|
361
|
+
res = t('example.com')
|
|
362
|
+
res = t('http://example.com', {'Accept': '*/*'}, b'Hi!')
|
|
363
|
+
res = t('http://example.com', {'Accept': '*/*'}, form={'a': 'b'})
|
|
364
|
+
res = t('http://example.com', {'Accept': '*/*'}, json={'a': 'b'})
|
|
365
|
+
|
|
366
|
+
Perform ``PATCH`` request with :attr:`Pyjo.UserAgent.Pyjo_UserAgent.patch`
|
|
367
|
+
and return resulting :mod:`Pyjo.Message.Response` object.
|
|
368
|
+
"""
|
|
369
|
+
return _ua().patch(*args, **kwargs).result
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
# Not in Mojolicious: characters, as Pyjo.String.Unicode is Mojo::ByteStream for them, where b is for bytes
|
|
373
|
+
def u(*parts: object) -> 'Pyjo.String.Unicode.object':
|
|
374
|
+
"""::
|
|
375
|
+
|
|
376
|
+
stream = u('lalala')
|
|
377
|
+
|
|
378
|
+
Turn string into a :mod:`Pyjo.String.Unicode` object. ::
|
|
379
|
+
|
|
380
|
+
$ python -m Pyjo 'u(g("mojolicious.org").text).html_unescape().say()'
|
|
381
|
+
"""
|
|
382
|
+
import Pyjo.String.Unicode
|
|
383
|
+
|
|
384
|
+
return Pyjo.String.Unicode.u(*parts)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
# Renamed from Mojolicious: u, as u is for characters, as in Pyjo.String.Unicode
|
|
388
|
+
def w(*args: Any, **kwargs: Any) -> 'Pyjo.Message.Response.object':
|
|
389
|
+
"""::
|
|
390
|
+
|
|
391
|
+
res = w('example.com')
|
|
392
|
+
res = w('http://example.com', {'Accept': '*/*'}, b'Hi!')
|
|
393
|
+
res = w('http://example.com', {'Accept': '*/*'}, form={'a': 'b'})
|
|
394
|
+
res = w('http://example.com', {'Accept': '*/*'}, json={'a': 'b'})
|
|
395
|
+
|
|
396
|
+
Perform ``PUT`` request with :attr:`Pyjo.UserAgent.Pyjo_UserAgent.put` and
|
|
397
|
+
return resulting :mod:`Pyjo.Message.Response` object.
|
|
398
|
+
"""
|
|
399
|
+
return _ua().put(*args, **kwargs).result
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def x(*args: Any) -> 'Pyjo.DOM.object':
|
|
403
|
+
"""::
|
|
404
|
+
|
|
405
|
+
dom = x('<div>Hello!</div>')
|
|
406
|
+
|
|
407
|
+
Turn HTML/XML input into :mod:`Pyjo.DOM` object. ::
|
|
408
|
+
|
|
409
|
+
$ python -m Pyjo 'x(f("test.html").slurp()).at("title").text'
|
|
410
|
+
"""
|
|
411
|
+
import Pyjo.DOM
|
|
412
|
+
|
|
413
|
+
return Pyjo.DOM.new(*args)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
# Not in Mojolicious: the builder of Pyjo.JSON.Schema, as z of zod, which imports the module when one of its methods is
|
|
417
|
+
# read, so that from Pyjo import * does not import it
|
|
418
|
+
class _Builder:
|
|
419
|
+
def __getattr__(self, name: str) -> Any:
|
|
420
|
+
import Pyjo.JSON.Schema
|
|
421
|
+
|
|
422
|
+
return getattr(Pyjo.JSON.Schema.z, name)
|
|
423
|
+
|
|
424
|
+
def __repr__(self) -> str:
|
|
425
|
+
return 'Pyjo.JSON.Schema.z'
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
if TYPE_CHECKING:
|
|
429
|
+
z = Pyjo.JSON.Schema.z
|
|
430
|
+
else:
|
|
431
|
+
z = _Builder()
|
|
432
|
+
"""::
|
|
433
|
+
|
|
434
|
+
schema = z.object(name=z.string(), stars=z.int().min(0))
|
|
435
|
+
|
|
436
|
+
The builder of :mod:`Pyjo.JSON.Schema`, its class ``z``, after ``z`` of
|
|
437
|
+
zod, whose schemas validate a value, as the JSON of a response. ::
|
|
438
|
+
|
|
439
|
+
$ python -m Pyjo 'z.object(port=z.int()).validate(j(f("config.json").slurp()))'
|
|
440
|
+
$ python -m Pyjo 'z.object(id=z.int()).validate(g("api.github.com/repos/dex4er/Pyjoyment").json()).is_valid'
|
|
441
|
+
"""
|
Pyjo/__main__.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Run a one-liner with the functions of :mod:`Pyjo`, as ``perl -Mojo -E`` does,
|
|
3
|
+
and print the value of an expression. ::
|
|
4
|
+
|
|
5
|
+
$ python -m Pyjo 'g("mojolicious.org").dom().at("title").text'
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import Pyjo
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Not in Mojolicious: perl -Mojo -E, as Python has no import on its command line that a one-liner can name
|
|
15
|
+
def main(argv: list[str] | None = None) -> None:
|
|
16
|
+
args = sys.argv[1:] if argv is None else argv
|
|
17
|
+
if not args:
|
|
18
|
+
sys.exit('usage: python -m Pyjo CODE [ARGS...]')
|
|
19
|
+
code, sys.argv = args[0], ['-c', *args[1:]]
|
|
20
|
+
|
|
21
|
+
# Silent one-liners
|
|
22
|
+
os.environ.setdefault('PYJO_LOG_LEVEL', 'fatal')
|
|
23
|
+
|
|
24
|
+
namespace = {'__name__': '__main__', **{name: getattr(Pyjo, name) for name in Pyjo.__all__}}
|
|
25
|
+
try:
|
|
26
|
+
expression = compile(code, '<string>', 'eval')
|
|
27
|
+
except SyntaxError:
|
|
28
|
+
exec(compile(code, '<string>', 'exec'), namespace)
|
|
29
|
+
return
|
|
30
|
+
if (value := eval(expression, namespace)) is not None:
|
|
31
|
+
print(value)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if __name__ == '__main__':
|
|
35
|
+
main()
|
Pyjo/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjoyment.Command.Author - Author commands
|
|
3
|
+
==========================================
|
|
4
|
+
|
|
5
|
+
``Pyjoyment.Command.Author`` is the namespace of the commands for the authors
|
|
6
|
+
of applications and plugins, as :mod:`Pyjoyment.Command.Author.generate` and
|
|
7
|
+
:mod:`Pyjoyment.Command.Author.inflate`, which :mod:`Pyjoyment.Commands`
|
|
8
|
+
loads before the ones of ``Pyjoyment.Command``.
|
|
9
|
+
|
|
10
|
+
See also
|
|
11
|
+
--------
|
|
12
|
+
|
|
13
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from pkgutil import extend_path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Not in Mojolicious: a namespace that other distributions can add commands to
|
|
20
|
+
__path__ = extend_path(__path__, __name__)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjoyment.Command.Author.generate - Generator command
|
|
3
|
+
=====================================================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
Usage: APPLICATION generate GENERATOR [OPTIONS]
|
|
7
|
+
|
|
8
|
+
pyjo generate app
|
|
9
|
+
pyjo generate lite-app
|
|
10
|
+
|
|
11
|
+
:mod:`Pyjoyment.Command.Author.generate` lists available generators.
|
|
12
|
+
|
|
13
|
+
This is a core command, that means it is always enabled and its code a good
|
|
14
|
+
example for learning to build new commands, you're welcome to fork it.
|
|
15
|
+
|
|
16
|
+
See :mod:`Pyjoyment.Commands` for a list of commands that are available by
|
|
17
|
+
default.
|
|
18
|
+
|
|
19
|
+
See also
|
|
20
|
+
--------
|
|
21
|
+
|
|
22
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
23
|
+
|
|
24
|
+
Ported from `Mojolicious::Command::Author::generate
|
|
25
|
+
<https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojolicious/Command/Author/generate.pm>`_ of Mojolicious 9.49.
|
|
26
|
+
|
|
27
|
+
Classes
|
|
28
|
+
-------
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
import Pyjoyment.Commands
|
|
32
|
+
|
|
33
|
+
from pkgutil import extend_path
|
|
34
|
+
from typing import Any
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Pyjoyment_Command_Author_generate(Pyjoyment.Commands.object):
|
|
38
|
+
"""
|
|
39
|
+
:mod:`Pyjoyment.Command.Author.generate` inherits all attributes and
|
|
40
|
+
methods from :mod:`Pyjoyment.Commands` and implements the following new
|
|
41
|
+
ones.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
description = 'Generate files and directories from templates'
|
|
45
|
+
"""::
|
|
46
|
+
|
|
47
|
+
description = generator.description
|
|
48
|
+
generator.description = 'Foo'
|
|
49
|
+
|
|
50
|
+
Short description of this command, used for the command list.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
hint = "\nSee 'APPLICATION generate help GENERATOR' for more information on a specific\ngenerator.\n"
|
|
54
|
+
"""::
|
|
55
|
+
|
|
56
|
+
hint = generator.hint
|
|
57
|
+
generator.hint = 'Foo'
|
|
58
|
+
|
|
59
|
+
Short hint shown after listing available generator commands.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
63
|
+
super().__init__(**kwargs)
|
|
64
|
+
if 'namespaces' not in kwargs:
|
|
65
|
+
self.namespaces = ['Pyjoyment.Command.Author.generate']
|
|
66
|
+
"""::
|
|
67
|
+
|
|
68
|
+
namespaces = generator.namespaces
|
|
69
|
+
generator.namespaces = ['MyApp.Command.generate']
|
|
70
|
+
|
|
71
|
+
Namespaces to search for available generator commands, defaults to
|
|
72
|
+
``Pyjoyment.Command.Author.generate``.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def message(self) -> str:
|
|
77
|
+
"""::
|
|
78
|
+
|
|
79
|
+
msg = generator.message
|
|
80
|
+
generator.message = 'Bar'
|
|
81
|
+
|
|
82
|
+
Short usage message shown before listing available generator commands.
|
|
83
|
+
"""
|
|
84
|
+
if self._message is None:
|
|
85
|
+
self._message = self.extract_usage() + '\nGenerators:\n'
|
|
86
|
+
return self._message
|
|
87
|
+
|
|
88
|
+
@message.setter
|
|
89
|
+
def message(self, value: str) -> None:
|
|
90
|
+
self._message = value
|
|
91
|
+
|
|
92
|
+
def help(self, *args: str) -> Any:
|
|
93
|
+
"""::
|
|
94
|
+
|
|
95
|
+
generator.help('app')
|
|
96
|
+
|
|
97
|
+
Print usage information for generator command.
|
|
98
|
+
"""
|
|
99
|
+
return self.run(*args)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Not in Mojolicious: a namespace that other distributions can add generators to
|
|
103
|
+
__path__ = extend_path(__path__, __name__)
|
|
104
|
+
|
|
105
|
+
new = Pyjoyment_Command_Author_generate.new
|
|
106
|
+
object = Pyjoyment_Command_Author_generate
|