Pyjoyment 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. Pyjo/App/ASGI.py +735 -0
  2. Pyjo/App/CGI.py +773 -0
  3. Pyjo/App/FastCGI.py +631 -0
  4. Pyjo/App/Lambda.py +987 -0
  5. Pyjo/App/WSGI.py +427 -0
  6. Pyjo/App/__init__.py +409 -0
  7. Pyjo/Asset/File.py +377 -0
  8. Pyjo/Asset/Memory.py +235 -0
  9. Pyjo/Asset/__init__.py +200 -0
  10. Pyjo/Base.py +215 -0
  11. Pyjo/Cache.py +119 -0
  12. Pyjo/Collection.py +570 -0
  13. Pyjo/Content/MultiPart.py +325 -0
  14. Pyjo/Content/Single.py +193 -0
  15. Pyjo/Content/__init__.py +806 -0
  16. Pyjo/Cookie/Request.py +90 -0
  17. Pyjo/Cookie/Response.py +294 -0
  18. Pyjo/Cookie/__init__.py +143 -0
  19. Pyjo/DOM/CSS.py +1019 -0
  20. Pyjo/DOM/HTML.py +550 -0
  21. Pyjo/DOM/__init__.py +1329 -0
  22. Pyjo/Date.py +294 -0
  23. Pyjo/EventEmitter.py +522 -0
  24. Pyjo/Exception.py +494 -0
  25. Pyjo/File.py +959 -0
  26. Pyjo/GetOpt.py +605 -0
  27. Pyjo/Headers.py +760 -0
  28. Pyjo/HelloWorld.py +77 -0
  29. Pyjo/Home.py +109 -0
  30. Pyjo/IOLoop/ChildProcess.py +591 -0
  31. Pyjo/IOLoop/Client.py +736 -0
  32. Pyjo/IOLoop/Datagram.py +982 -0
  33. Pyjo/IOLoop/Messages.py +664 -0
  34. Pyjo/IOLoop/Server.py +458 -0
  35. Pyjo/IOLoop/Stdio.py +446 -0
  36. Pyjo/IOLoop/Stream.py +644 -0
  37. Pyjo/IOLoop/Subprocess.py +419 -0
  38. Pyjo/IOLoop/TLS.py +360 -0
  39. Pyjo/IOLoop/__init__.py +1036 -0
  40. Pyjo/IOLoop/certs/README.md +41 -0
  41. Pyjo/IOLoop/certs/ca.crt +20 -0
  42. Pyjo/IOLoop/certs/server.crt +21 -0
  43. Pyjo/IOLoop/certs/server.key +28 -0
  44. Pyjo/JSON/Pointer.py +135 -0
  45. Pyjo/JSON/RPC.py +772 -0
  46. Pyjo/JSON/Schema.py +2506 -0
  47. Pyjo/JSON/__init__.py +573 -0
  48. Pyjo/Loader.py +342 -0
  49. Pyjo/Log.py +723 -0
  50. Pyjo/Message/Request.py +725 -0
  51. Pyjo/Message/Response.py +476 -0
  52. Pyjo/Message/__init__.py +830 -0
  53. Pyjo/Parameters.py +472 -0
  54. Pyjo/Path.py +419 -0
  55. Pyjo/Promise.py +894 -0
  56. Pyjo/Prove.py +1305 -0
  57. Pyjo/Reactor/Asyncio.py +854 -0
  58. Pyjo/Reactor/Poll.py +439 -0
  59. Pyjo/Reactor/__init__.py +525 -0
  60. Pyjo/SSE.py +119 -0
  61. Pyjo/Server/ASGI.py +486 -0
  62. Pyjo/Server/CGI.py +259 -0
  63. Pyjo/Server/Daemon.py +1007 -0
  64. Pyjo/Server/FastCGI.py +517 -0
  65. Pyjo/Server/Hot/__init__.py +687 -0
  66. Pyjo/Server/Hot/__main__.py +5 -0
  67. Pyjo/Server/Lambda.py +641 -0
  68. Pyjo/Server/Prefork.py +917 -0
  69. Pyjo/Server/Prethread.py +394 -0
  70. Pyjo/Server/Reload/Backend/Poll.py +114 -0
  71. Pyjo/Server/Reload/Backend/__init__.py +126 -0
  72. Pyjo/Server/Reload/__init__.py +482 -0
  73. Pyjo/Server/Reload/__main__.py +5 -0
  74. Pyjo/Server/Stdio.py +228 -0
  75. Pyjo/Server/WSGI.py +349 -0
  76. Pyjo/Server/__init__.py +396 -0
  77. Pyjo/String/Bytes.py +532 -0
  78. Pyjo/String/HTML.py +210 -0
  79. Pyjo/String/Mixin.py +333 -0
  80. Pyjo/String/Template.py +470 -0
  81. Pyjo/String/Unicode.py +553 -0
  82. Pyjo/String/__init__.py +0 -0
  83. Pyjo/TOML.py +232 -0
  84. Pyjo/Template.py +1290 -0
  85. Pyjo/Test/Pyjo.py +1454 -0
  86. Pyjo/Test/__init__.py +1233 -0
  87. Pyjo/Test/pytest_plugin.py +305 -0
  88. Pyjo/Transaction/HTTP.py +374 -0
  89. Pyjo/Transaction/WebSocket.py +709 -0
  90. Pyjo/Transaction/__init__.py +429 -0
  91. Pyjo/URL/Template.py +459 -0
  92. Pyjo/URL/__init__.py +651 -0
  93. Pyjo/Upload.py +139 -0
  94. Pyjo/UserAgent/CookieJar.py +391 -0
  95. Pyjo/UserAgent/Proxy.py +138 -0
  96. Pyjo/UserAgent/Server.py +239 -0
  97. Pyjo/UserAgent/Transactor.py +766 -0
  98. Pyjo/UserAgent/__init__.py +1243 -0
  99. Pyjo/Util.py +3567 -0
  100. Pyjo/WebSocket.py +332 -0
  101. Pyjo/YAML.py +1167 -0
  102. Pyjo/__init__.py +441 -0
  103. Pyjo/__main__.py +35 -0
  104. Pyjo/py.typed +0 -0
  105. Pyjoyment/Command/Author/__init__.py +20 -0
  106. Pyjoyment/Command/Author/generate/__init__.py +106 -0
  107. Pyjoyment/Command/Author/generate/app.py +299 -0
  108. Pyjoyment/Command/Author/generate/dockerfile.py +281 -0
  109. Pyjoyment/Command/Author/generate/kubernetes.py +514 -0
  110. Pyjoyment/Command/Author/generate/lambda_zip.py +372 -0
  111. Pyjoyment/Command/Author/generate/lite_app.py +113 -0
  112. Pyjoyment/Command/Author/generate/plugin.py +267 -0
  113. Pyjoyment/Command/Author/generate/pyproject.py +123 -0
  114. Pyjoyment/Command/Author/inflate.py +101 -0
  115. Pyjoyment/Command/__init__.py +332 -0
  116. Pyjoyment/Command/asgi.py +92 -0
  117. Pyjoyment/Command/cgi.py +90 -0
  118. Pyjoyment/Command/daemon.py +160 -0
  119. Pyjoyment/Command/eval.py +128 -0
  120. Pyjoyment/Command/fastcgi.py +99 -0
  121. Pyjoyment/Command/get.py +305 -0
  122. Pyjoyment/Command/lambda.py +117 -0
  123. Pyjoyment/Command/prefork.py +181 -0
  124. Pyjoyment/Command/prethread.py +126 -0
  125. Pyjoyment/Command/routes.py +133 -0
  126. Pyjoyment/Command/stdio.py +92 -0
  127. Pyjoyment/Command/version.py +141 -0
  128. Pyjoyment/Command/wsgi.py +93 -0
  129. Pyjoyment/Commands.py +546 -0
  130. Pyjoyment/Controller.py +1307 -0
  131. Pyjoyment/HelloWorld.py +56 -0
  132. Pyjoyment/Lite.py +494 -0
  133. Pyjoyment/Plugin/AllowedHosts.py +205 -0
  134. Pyjoyment/Plugin/Config.py +248 -0
  135. Pyjoyment/Plugin/DefaultHelpers.py +1202 -0
  136. Pyjoyment/Plugin/EPLRenderer.py +134 -0
  137. Pyjoyment/Plugin/EPRenderer.py +212 -0
  138. Pyjoyment/Plugin/HeaderCondition.py +98 -0
  139. Pyjoyment/Plugin/Health.py +325 -0
  140. Pyjoyment/Plugin/JSONConfig.py +172 -0
  141. Pyjoyment/Plugin/Mount.py +223 -0
  142. Pyjoyment/Plugin/PyRenderer.py +209 -0
  143. Pyjoyment/Plugin/TOMLConfig.py +141 -0
  144. Pyjoyment/Plugin/TagHelpers.py +959 -0
  145. Pyjoyment/Plugin/YAMLConfig.py +178 -0
  146. Pyjoyment/Plugin/__init__.py +80 -0
  147. Pyjoyment/Plugins.py +215 -0
  148. Pyjoyment/Renderer.py +673 -0
  149. Pyjoyment/Routes/Match.py +251 -0
  150. Pyjoyment/Routes/Pattern.py +443 -0
  151. Pyjoyment/Routes/Route.py +827 -0
  152. Pyjoyment/Routes/__init__.py +419 -0
  153. Pyjoyment/Sessions.py +255 -0
  154. Pyjoyment/Static.py +421 -0
  155. Pyjoyment/Types.py +238 -0
  156. Pyjoyment/Validator/Validation.py +395 -0
  157. Pyjoyment/Validator/__init__.py +304 -0
  158. Pyjoyment/__init__.py +1083 -0
  159. Pyjoyment/__main__.py +5 -0
  160. Pyjoyment/py.typed +0 -0
  161. Pyjoyment/resources/public/favicon.ico +0 -0
  162. Pyjoyment/resources/public/favicon.svg +345 -0
  163. Pyjoyment/resources/public/pyjo/bootstrap/LICENSE +21 -0
  164. Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.bundle.min.js.map +1 -0
  165. Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.css +6 -0
  166. Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.js +7 -0
  167. Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.min.css.map +1 -0
  168. Pyjoyment/resources/public/pyjo/failunicat.png +0 -0
  169. Pyjoyment/resources/public/pyjo/failunicat.svg +50 -0
  170. Pyjoyment/resources/public/pyjo/highlight.js/LICENSE +29 -0
  171. Pyjoyment/resources/public/pyjo/highlight.js/highlight-mojo-dark.css +56 -0
  172. Pyjoyment/resources/public/pyjo/highlight.js/highlight.min.js +1262 -0
  173. Pyjoyment/resources/public/pyjo/highlight.js/pyjoyment.min.js +1 -0
  174. Pyjoyment/resources/public/pyjo/logo-black-4x.png +0 -0
  175. Pyjoyment/resources/public/pyjo/logo-black-4x.svg +346 -0
  176. Pyjoyment/resources/public/pyjo/logo-white-2x.png +0 -0
  177. Pyjoyment/resources/public/pyjo/logo-white-2x.svg +346 -0
  178. Pyjoyment/resources/public/pyjo/logo-white-4x.png +0 -0
  179. Pyjoyment/resources/public/pyjo/logo-white-4x.svg +346 -0
  180. Pyjoyment/resources/public/pyjo/logo-white.png +0 -0
  181. Pyjoyment/resources/public/pyjo/logo-white.svg +346 -0
  182. Pyjoyment/resources/public/pyjo/logo.png +0 -0
  183. Pyjoyment/resources/public/pyjo/logo.svg +346 -0
  184. Pyjoyment/resources/public/pyjo/notfound.png +0 -0
  185. Pyjoyment/resources/public/pyjo/notfound.svg +3 -0
  186. Pyjoyment/resources/public/pyjo/nounicat.png +0 -0
  187. Pyjoyment/resources/public/pyjo/nounicat.svg +5 -0
  188. Pyjoyment/resources/public/pyjo/pinstripe-dark.png +0 -0
  189. Pyjoyment/resources/public/pyjo/pinstripe-dark.svg +4 -0
  190. Pyjoyment/resources/public/pyjo/pinstripe-light.png +0 -0
  191. Pyjoyment/resources/public/pyjo/pinstripe-light.svg +4 -0
  192. Pyjoyment/resources/public/pyjo/pyjo.css +204 -0
  193. Pyjoyment/resources/templates/pyjo/debug.html.ep +346 -0
  194. Pyjoyment/resources/templates/pyjo/exception.html.ep +32 -0
  195. Pyjoyment/resources/templates/pyjo/not_found.html.ep +45 -0
  196. pyjoyment-0.1.0.dist-info/METADATA +376 -0
  197. pyjoyment-0.1.0.dist-info/RECORD +200 -0
  198. pyjoyment-0.1.0.dist-info/WHEEL +4 -0
  199. pyjoyment-0.1.0.dist-info/entry_points.txt +8 -0
  200. pyjoyment-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,204 @@
1
+ html {
2
+ height:100%;
3
+ }
4
+ body {
5
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
6
+ "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji",
7
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
8
+ }
9
+ main {
10
+ overflow-wrap: break-word;
11
+ word-wrap: break-word;
12
+ }
13
+ .navbar {
14
+ --bs-navbar-padding-x: 1rem;
15
+ --bs-navbar-padding-y: .5rem;
16
+ }
17
+ :not(pre) > code {
18
+ background-color: #eef9ff;
19
+ border: solid #cce4ff 1px;
20
+ border-radius: .25rem;
21
+ color: #333;
22
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
23
+ padding: 0.4em;
24
+ }
25
+ h2 {
26
+ font-weight: 300;
27
+ font-size: 2em;
28
+ }
29
+ pre {
30
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
31
+ margin: 0;
32
+ white-space: pre-wrap;
33
+ }
34
+ pre > code {
35
+ display: block;
36
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
37
+ margin-bottom: 0.7em;
38
+ margin-top: 0.7em;
39
+ }
40
+ table {
41
+ border-collapse: collapse;
42
+ width: 100%;
43
+ }
44
+ td {
45
+ padding: 0.5em;
46
+ }
47
+ th {
48
+ padding-left: 1em;
49
+ }
50
+ .border-radius-bottom {
51
+ border-radius: 0 0 .25rem .25rem;
52
+ }
53
+ .border-radius-both {
54
+ border-radius: .25rem;
55
+ }
56
+ .border-radius-top {
57
+ border-radius: .25rem .25rem 0 0;
58
+ }
59
+ .box {
60
+ background-color: #fff;
61
+ border: 1px solid #e1e4e8;
62
+ overflow: hidden;
63
+ padding: 1em;
64
+ width: 100%;
65
+ }
66
+ .code {
67
+ background-color: #282c34;;
68
+ background: url(../pyjo/pinstripe-dark.png);
69
+ color: #eee;
70
+ text-shadow: #333 0 1px 0;
71
+ }
72
+ .context-value {
73
+ padding: 0;
74
+ padding-left: 1em;
75
+ }
76
+ .error {
77
+ color: #fff;
78
+ font: 1.5em 'Helvetica Neue', Helvetica, sans-serif;
79
+ font-weight: 300;
80
+ margin: 0;
81
+ }
82
+ .fixed-table {
83
+ table-layout: fixed;
84
+ }
85
+ .important {
86
+ background-color: rgba(47, 48, 50, .75);
87
+ }
88
+ .key {
89
+ width: 20%;
90
+ }
91
+ .mojobar {
92
+ background-color: #1a1a1a;
93
+ }
94
+ .mojobar #navbarNav .nav-link {
95
+ color: #bbb;
96
+ }
97
+ .mojobar #navbarNav .nav-link:hover {
98
+ color: #fff;
99
+ }
100
+ .mojobar #navbarNav input[type=search] {
101
+ background-color: #3a3a3a;
102
+ border: 1px solid rgba(0, 0, 0, 0.1);
103
+ border-radius: 3px;
104
+ color: #eee;
105
+ padding: 6px;
106
+ margin-left: 1em;
107
+ transition: all 0.15s;
108
+ }
109
+ .mojobar #navbarNav input[type="search"]:focus {
110
+ background-color: #fff;
111
+ color: #111;
112
+ outline: 0;
113
+ }
114
+ .mojo-divider {
115
+ padding-bottom: 1em;
116
+ }
117
+ .mojo-copy {
118
+ font-size: 12px;
119
+ }
120
+ .mojo-copy, .mojo-copy a {
121
+ color: #777;
122
+ }
123
+ .mojo-footer {
124
+ background: url(../pyjo/pinstripe-light.png);
125
+ background-color: #f2ece9;
126
+ box-shadow: inset 0 10px 10px -5px #ddd;
127
+ color: #666;
128
+ }
129
+ .mojo-footer a:hover {
130
+ color: #000;
131
+ text-decoration: none;
132
+ }
133
+ .mojo-social a {
134
+ color: #666;
135
+ font-size: 1.5em;
136
+ padding: 0.2em;
137
+ }
138
+ .mojo-terminal {
139
+ background-color: #282c34;
140
+ border: 0;
141
+ border-radius: .25rem;
142
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
143
+ padding: 1em;
144
+ width: 100%;
145
+ }
146
+ .mojo-terminal > code {
147
+ color: #eee;
148
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
149
+ line-height: 1.5em;
150
+ text-align: left;
151
+ white-space: pre-wrap;
152
+ }
153
+ .no-bottom-border {
154
+ border-bottom: 0;
155
+ }
156
+ .no-padding {
157
+ padding: 0;
158
+ }
159
+ .no-top-border {
160
+ border-top: 0;
161
+ }
162
+ .padded-content {
163
+ padding: 1em;
164
+ }
165
+ .striped tr:nth-child(odd) .value {
166
+ background-color: #ddeeff;
167
+ }
168
+ .striped tr:nth-child(even) .value {
169
+ background-color: #eef9ff;
170
+ }
171
+ .striped .key {
172
+ border-right: 1px solid #e1e4e8;
173
+ }
174
+ .striped tr:not(:first-of-type) .value {
175
+ border-top: solid #cce4ff 1px;
176
+ }
177
+ .striped-grey .value {
178
+ border-top: solid #e1e4e8 1px;
179
+ }
180
+ .tap {
181
+ font: 0.5em Verdana, sans-serif;
182
+ padding: 20px;
183
+ text-align: center;
184
+ }
185
+ .tap-border-top, #infos {
186
+ border-top: 1px solid #e1e4e8;
187
+ }
188
+ .tooltip code {
189
+ background: 0;
190
+ border: 0;
191
+ border-radius: 0;
192
+ color: #eee;
193
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;;
194
+ padding: 0;
195
+ }
196
+ .value {
197
+ padding: 1em;
198
+ }
199
+ .value pre {
200
+ padding-right: 1em;
201
+ }
202
+ .wide {
203
+ width: 100%;
204
+ }
@@ -0,0 +1,346 @@
1
+ % import importlib.metadata, os, platform, sys, time
2
+ %# Renamed from Mojolicious: the files of the page are in pyjo/, where Mojo has them in mojo/, its stylesheet is
3
+ %# pyjo/pyjo.css, where Mojo has mojo/mojo.css, and the language of highlight.js for templates is pyjoyment, where Mojo
4
+ %# has mojolicious; the links of the page are those of Pyjoyment
5
+ <!DOCTYPE html>
6
+ <!-- Request ID: <%= c.req.request_id %> -->
7
+ <html>
8
+ <head>
9
+ % title = 'Server Error' if stash('exception') else 'Page Not Found'
10
+ <title><%= title %> (<%= c.app.mode %> mode)</title>
11
+ <meta http-equiv="Pragma" content="no-cache">
12
+ <meta http-equiv="Expires" content="-1">
13
+ %= favicon()
14
+ %= javascript('/pyjo/highlight.js/highlight.min.js')
15
+ %= javascript('/pyjo/highlight.js/pyjoyment.min.js')
16
+ %# Left out from Mojolicious: popper.js, as bootstrap.js is the bundle of Bootstrap, which has Popper
17
+ %= javascript('/pyjo/bootstrap/bootstrap.js')
18
+ %= stylesheet('/pyjo/bootstrap/bootstrap.css')
19
+ %= stylesheet('/pyjo/highlight.js/highlight-mojo-dark.css')
20
+ %= stylesheet('/pyjo/pyjo.css')
21
+ <script>
22
+ 'use strict';
23
+ %# Unlike Mojolicious: highlightAll of highlight.js 11, where Mojo calls initHighlightingOnLoad of highlight.js 10,
24
+ %# which highlight.js 11 deprecates
25
+ hljs.highlightAll();
26
+ window.addEventListener('load', () => {
27
+ for (const tooltip of document.querySelectorAll('[data-bs-toggle="tooltip"]')) {
28
+ new bootstrap.Tooltip(tooltip);
29
+ }
30
+ });
31
+ </script>
32
+ <style>
33
+ .social-icon {
34
+ width: 32px;
35
+ display: inline-block;
36
+ line-height: 24px;
37
+ }
38
+ </style>
39
+ </head>
40
+ <body class="d-flex flex-column h-100">
41
+ <header>
42
+ <nav class="navbar navbar-expand-lg navbar-dark mojobar">
43
+ <a href="https://pyjoyment.readthedocs.io/" id="mojobar-brand" class="navbar-brand">
44
+ <picture>
45
+ <img src="<%= url_for_file('/pyjo/logo-white.png') %>"
46
+ srcset="<%= url_for_file('/pyjo/logo-white-2x.png') %> 2x">
47
+ </picture>
48
+ </a>
49
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav"
50
+ aria-expanded="false" aria-label="Toggle navigation">
51
+ <span class="navbar-toggler-icon"></span>
52
+ </button>
53
+ <div id="navbarNav" class="collapse navbar-collapse">
54
+ <ul class="navbar-nav me-auto">
55
+ <li class="nav-item dropdown">
56
+ <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown"
57
+ aria-haspopup="true" aria-expanded="false">
58
+ Documentation
59
+ </a>
60
+ <div class="dropdown-menu" aria-labelledby="navbarDropdown">
61
+ <a class="dropdown-item" href="https://pyjoyment.readthedocs.io/">Overview</a>
62
+ <div class="dropdown-divider"></div>
63
+ <a class="dropdown-item" href="https://pyjoyment.readthedocs.io/en/latest/intro.html">Introduction</a>
64
+ <a class="dropdown-item" href="https://pyjoyment.readthedocs.io/en/latest/status.html">Status</a>
65
+ <a class="dropdown-item" href="https://pyjoyment.readthedocs.io/en/latest/installation.html">Installation</a>
66
+ <a class="dropdown-item" href="https://pyjoyment.readthedocs.io/en/latest/examples.html">Examples</a>
67
+ <div class="dropdown-divider"></div>
68
+ <a class="dropdown-item" href="https://pyjoyment.readthedocs.io/en/latest/api/index.html">API</a>
69
+ </div>
70
+ </li>
71
+ <li class="nav-item dropdown">
72
+ <a class="nav-link dropdown-toggle" href="#" id="communityDropdown" role="button" data-bs-toggle="dropdown"
73
+ aria-haspopup="true" aria-expanded="false">
74
+ Community
75
+ </a>
76
+ <div class="dropdown-menu" aria-labelledby="communityDropdown">
77
+ <a class="dropdown-item" href="https://github.com/dex4er/Pyjoyment/issues">Issues</a>
78
+ <a class="dropdown-item" href="https://pypi.org/project/Pyjoyment/">PyPI</a>
79
+ <a class="dropdown-item" href="https://mojolicious.org">Mojolicious</a>
80
+ </div>
81
+ </li>
82
+ <li class="nav-item">
83
+ <a class="nav-link" href="https://github.com/dex4er/Pyjoyment/">Contribute on GitHub</a>
84
+ </li>
85
+ </ul>
86
+ %# Left out from Mojolicious: the form of the search, as it searches the documentation of Mojolicious
87
+ </div>
88
+ </nav>
89
+ </header>
90
+ <script>
91
+ 'use strict';
92
+ function mojoDrawer(handle, drawer) {
93
+ const handleEl = document.querySelector(handle);
94
+ if (handleEl === null) return;
95
+ handleEl.addEventListener('click', () => {
96
+ const drawerEl = document.querySelector(drawer);
97
+ let text = handleEl.innerText;
98
+ text = text == "tap for more" ? "tap for less" : "tap for more";
99
+ const divTap = document.querySelector(handle + ' div.tap');
100
+ if (divTap !== null) divTap.innerText = text;
101
+ drawerEl.classList.toggle('d-none');
102
+ });
103
+ }
104
+ window.addEventListener('load', () => {
105
+ mojoDrawer('#trace', '#frames');
106
+ mojoDrawer('#more', '#infos');
107
+ });
108
+ </script>
109
+ <div class="container flex-grow-1">
110
+ <div class="row flex-wrap">
111
+ <main class="col-sm-12 col-md-8 col-lg-10 py-md-3 pl-md-5">
112
+ <div class="row mojo-divider">
113
+ % kv = begin
114
+ % key, value = args
115
+ <tr>
116
+ <td class="key text-right"><%= key %>:</td>
117
+ <td class="value"><pre><%= value %></pre></td>
118
+ </tr>
119
+ % end
120
+ % if (exception := stash('exception')) {
121
+ <div class="alert alert-danger wide" role="alert">
122
+ <h2>Server Error</h2>
123
+ This application is in <b>development</b> mode and will show internal information to help you with
124
+ debugging.
125
+ </div>
126
+ % cv = begin
127
+ % key, value, i = [*args, None][:3]
128
+ %= tag('tr', begin
129
+ <td class="text-right"><%= key %></td>
130
+ <td class="context-value wide">
131
+ <pre><code><%= value %></code></pre>
132
+ </td>
133
+ %= end, **({'class': 'important'} if i else {}))
134
+ % end
135
+ <div id="showcase" class="box code no-bottom-border no-top-border border-radius-top">
136
+ <pre id="error" class="error"><%= exception.message %></pre>
137
+ <div id="context" class="more">
138
+ <table class="wide">
139
+ % for line in exception.lines_before {
140
+ %= cv(line[0], line[1])
141
+ % }
142
+ % if len(exception.line) > 1 {
143
+ %= cv(exception.line[0], exception.line[1], 1)
144
+ % }
145
+ % for line in exception.lines_after {
146
+ %= cv(line[0], line[1])
147
+ % }
148
+ </table>
149
+ </div>
150
+ % if len(exception.line) > 2 {
151
+ <div id="insight">
152
+ <table class="wide">
153
+ % for line in exception.lines_before {
154
+ %= cv(line[0], line[2])
155
+ % }
156
+ %= cv(exception.line[0], exception.line[2], 1)
157
+ % for line in exception.lines_after {
158
+ %= cv(line[0], line[2])
159
+ % }
160
+ </table>
161
+ </div>
162
+ <div class="tap">tap for more</div>
163
+ <script>
164
+ 'use strict';
165
+ let current = '#context';
166
+ function mojoShowcase() {
167
+ const showcase = document.querySelector('#showcase');
168
+ function onClickShowcase() {
169
+ showcase.removeEventListener('click', onClickShowcase);
170
+ let currentEl = document.querySelector(current);
171
+ currentEl.classList.toggle('d-none');
172
+ current = current == '#context' ? '#insight' : '#context';
173
+ currentEl = document.querySelector(current);
174
+ currentEl.classList.toggle('d-none');
175
+ mojoShowcase();
176
+ };
177
+ showcase.addEventListener('click', onClickShowcase);
178
+ }
179
+ mojoShowcase();
180
+ const insightEl = document.querySelector('#insight');
181
+ insightEl.classList.toggle('d-none');
182
+ </script>
183
+ % }
184
+ </div>
185
+ <div id="trace" class="box no-padding more no-top-border border-radius-bottom">
186
+ % if exception.frames {
187
+ <div id="frames" class="d-none">
188
+ <table class="striped wide">
189
+ % for frame in exception.frames {
190
+ <tr>
191
+ <td class="value">
192
+ <pre>File "<%= frame.filename %>", line <%= frame.lineno %>, in "<%= frame.name %>"</pre>
193
+ </td>
194
+ </tr>
195
+ % }
196
+ </table>
197
+ </div>
198
+ <div class="tap">tap for more</div>
199
+ % }
200
+ </div>
201
+ % }
202
+ % else {
203
+ <div class="alert alert-warning wide" role="alert">
204
+ <h2>Page Not Found</h2>
205
+ This application is in <b>development</b> mode and will show internal information to help you with
206
+ debugging.
207
+ </div>
208
+ <div id="routes" class="box no-padding border-radius-both">
209
+ <div class="padded-content">
210
+ <p>
211
+ None of these routes could generate a response for your
212
+ <code><%= c.req.method %></code> request for
213
+ <code><%= c.req.url.path.to_route() %></code>, maybe you need
214
+ to add a new one?
215
+ </p>
216
+ </div>
217
+ % walk = begin
218
+ % walk, route, depth = args
219
+ % pattern = route.pattern
220
+ % unparsed = pattern.unparsed or '/'
221
+ % unparsed = f'+{unparsed}' if depth else unparsed
222
+ % pattern.match('/', route.is_endpoint and not route.partial)
223
+ % regex = pattern.regex.pattern
224
+ <tr data-bs-toggle="tooltip" data-bs-placement="left" data-bs-html="true"
225
+ data-bs-title="<b>Regex:</b> <code><%= regex %></code>">
226
+ <td class="value">
227
+ <pre><%= ' ' * depth %><%= unparsed %></pre>
228
+ </td>
229
+ <td class="value">
230
+ <pre><%= ','.join(route.methods() or []).upper() or '*' %></pre>
231
+ </td>
232
+ <td class="value">
233
+ % name = route.name
234
+ %# Unlike Mojolicious: the badge has the classes text-bg-success and text-bg-secondary of
235
+ %# Bootstrap 5, where Mojo has badge-success and badge-secondary of Bootstrap 4, which its
236
+ %# Bootstrap 5 has not, so that Mojo shows the name white on white
237
+ % badge = 'text-bg-success' if route.has_custom_name else 'text-bg-secondary'
238
+ <span class="badge <%= badge %>"><%= name %></span>
239
+ </td>
240
+ </tr>
241
+ % depth += 1
242
+ % for child in route.children {
243
+ %= walk(walk, child, depth)
244
+ % }
245
+ % depth -= 1
246
+ % end
247
+ <table class="striped-grey wide">
248
+ <thead>
249
+ <tr>
250
+ <th>Pattern</th>
251
+ <th>Methods</th>
252
+ <th>Name</th>
253
+ </tr>
254
+ </thead>
255
+ % for child in c.app.routes.children {
256
+ %= walk(walk, child, 0)
257
+ % }
258
+ </table>
259
+ </div>
260
+ % }
261
+ </div>
262
+ <div class="row mojo-divider">
263
+ <div id="request" class="box no-padding no-bottom-border border-radius-top">
264
+ <table class="striped fixed-table wide">
265
+ % req = c.req
266
+ %= kv('Request ID', req.request_id)
267
+ %= kv('Method', req.method)
268
+ % url = req.url
269
+ %= kv('URL', url.to_str())
270
+ %= kv('Base URL', url.base.to_str())
271
+ %= kv('Parameters', dumper(req.params.to_dict()))
272
+ %= kv('Stash', dumper(snapshot))
273
+ %= kv('Session', dumper(session()))
274
+ %= kv('Version', req.version)
275
+ % for name in sorted(c.req.headers.names()) {
276
+ % value = c.req.headers.header(name)
277
+ %= kv(name, value)
278
+ % }
279
+ </table>
280
+ </div>
281
+ <div id="more" class="box no-padding more no-top-border border-radius-bottom">
282
+ <div id="infos" class="d-none">
283
+ <table class="striped fixed-table wide">
284
+ %= kv('Python', f'{platform.python_implementation()} {platform.python_version()} ({sys.platform})')
285
+ % try {
286
+ % version = importlib.metadata.version('Pyjoyment')
287
+ % } except importlib.metadata.PackageNotFoundError {
288
+ % version = 'not installed'
289
+ % }
290
+ %# Left out from Mojolicious: the codename, as Pyjoyment has none
291
+ %= kv('Pyjoyment', version)
292
+ %= kv('Home', c.app.home)
293
+ %= kv('Template paths', dumper(c.app.renderer.paths))
294
+ %= kv('Template classes', dumper(c.app.renderer.classes))
295
+ %= kv('Static paths', dumper(c.app.static.paths))
296
+ %= kv('Static classes', dumper(c.app.static.classes))
297
+ %= kv('Include', dumper(sys.path))
298
+ %= kv('Config', dumper(c.app.config()))
299
+ %= kv('Moniker', c.app.moniker)
300
+ %= kv('Name', sys.argv[0])
301
+ %= kv('Executable', sys.executable)
302
+ %= kv('PID', os.getpid())
303
+ %= kv('Time', time.ctime())
304
+ </table>
305
+ </div>
306
+ <div class="tap tap-border-top">tap for more</div>
307
+ </div>
308
+ </div>
309
+ <div class="row">
310
+ % if c.app.log.history {
311
+ % log = ''.join(c.app.log.format(*entry) for entry in c.app.log.history)
312
+ <pre class="mojo-terminal"><code class="nohighlight"><%= log %></code></pre>
313
+ % }
314
+ % else {
315
+ <div class="alert alert-warning wide" role="alert">
316
+ The application log appears to be empty, perhaps the log level <b><%= c.app.log.level %></b> is too
317
+ high?
318
+ </div>
319
+ % }
320
+ </div>
321
+ </main>
322
+ </div>
323
+ </div>
324
+ <footer>
325
+ <div class="container-fluid p-3 mojo-footer">
326
+ <div class="row">
327
+ <div class="col-sm align-self-center text-center mojo-free">
328
+ <b>Free</b> and <b>Open Source</b>.
329
+ </div>
330
+ <div class="col-sm align-self-center text-center mojo-copy">
331
+ &copy; 2014-2026 Piotr Roszatycki, based on
332
+ <a href="https://mojolicious.org">Mojolicious</a> &copy; 2008-2025 Sebastian Riedel and the
333
+ <a href="https://docs.mojolicious.org/Mojolicious#AUTHORS">Mojolicious contributors</a>.
334
+ </div>
335
+ <div class="col-sm align-self-center text-center mojo-social">
336
+ %# The icon of GitHub is mark-github of Octicons, under the MIT License, https://github.com/primer/octicons
337
+ <a alt="GitHub" href="https://github.com/dex4er/Pyjoyment" class="social-icon">
338
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="height: 23px;"><path fill="currentColor" d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"/></svg>
339
+ </a>
340
+ %# Left out from Mojolicious: the links of Mastodon and LinkedIn, where Pyjoyment has no profiles
341
+ </div>
342
+ </div>
343
+ </div>
344
+ </footer>
345
+ </body>
346
+ </html>
@@ -0,0 +1,32 @@
1
+ %# Renamed from Mojolicious: the image of the unicat is pyjo/failunicat.png, where Mojo has mojo/failraptor.png, and
2
+ %# its element is #unicat, where Mojo has #raptor
3
+ <!DOCTYPE html>
4
+ <!-- Request ID: <%= c.req.request_id %> -->
5
+ <html>
6
+ <head>
7
+ <title>Server Error</title>
8
+ <style>
9
+ body {
10
+ background-color: #caecf6;
11
+ }
12
+ #unicat {
13
+ background: url(<%= url_for_file('/pyjo/failunicat.png') %>);
14
+ height: 488px;
15
+ left: 50%;
16
+ margin-left: -371px;
17
+ margin-top: -244px;
18
+ position:absolute;
19
+ top: 50%;
20
+ width: 743px;
21
+ }
22
+ </style>
23
+ %= favicon()
24
+ </head>
25
+ <body><div id="unicat"></div></body>
26
+ </html>
27
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
28
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
29
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
30
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
31
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
32
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
@@ -0,0 +1,45 @@
1
+ %# Renamed from Mojolicious: the image of the unicat is pyjo/nounicat.png, where Mojo has mojo/noraptor.png, and its
2
+ %# element is #nounicat, where Mojo has #noraptor
3
+ <!DOCTYPE html>
4
+ <!-- Request ID: <%= c.req.request_id %> -->
5
+ <html>
6
+ <head>
7
+ <title>Page Not Found</title>
8
+ <style>
9
+ a img {
10
+ border: 0;
11
+ }
12
+ body {
13
+ background-color: #caecf6;
14
+ }
15
+ #nounicat {
16
+ left: 0%;
17
+ position: fixed;
18
+ top: 60%;
19
+ }
20
+ #notfound {
21
+ background: url(<%= url_for_file('/pyjo/notfound.png') %>);
22
+ height: 62px;
23
+ left: 50%;
24
+ margin-left: -153px;
25
+ margin-top: -31px;
26
+ position:absolute;
27
+ top: 50%;
28
+ width: 306px;
29
+ }
30
+ </style>
31
+ %= favicon()
32
+ </head>
33
+ <body>
34
+ %= link_to(url_for().base, begin
35
+ %= image('/pyjo/nounicat.png', alt='Bye!', id='nounicat')
36
+ % end)
37
+ <div id="notfound"></div>
38
+ </body>
39
+ </html>
40
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
41
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
42
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
43
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
44
+ <!-- a padding to disable MSIE and Chrome friendly error page -->
45
+ <!-- a padding to disable MSIE and Chrome friendly error page -->