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
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