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/String/Bytes.py ADDED
@@ -0,0 +1,532 @@
1
+ r"""
2
+ Pyjo.String.Bytes - String of bytes
3
+ ===================================
4
+ ::
5
+
6
+ from Pyjo.String.Bytes import Bytes
7
+
8
+ # Manipulate bytes
9
+ data = Bytes(b'foo bar baz')
10
+ print(data.md5_sum())
11
+
12
+ # Or import the module, as in Google Python Style Guide
13
+
14
+ import Pyjo.String.Bytes
15
+
16
+ # Manipulate bytes
17
+ data = Pyjo.String.Bytes.new(b'foo bar baz')
18
+ print(data.md5_sum())
19
+
20
+ # Chain methods
21
+ data = Pyjo.String.Bytes.new(b'foo bar baz').quote()
22
+ string = data.unquote().b64_encode('')
23
+ print(string)
24
+
25
+ # Use the alternative constructor
26
+ from Pyjo.String.Bytes import b
27
+ string = b(b'foobarbaz').b64_encode('').say()
28
+
29
+ :mod:`Pyjo.String.Bytes` is a :class:`bytes` that provides a more friendly
30
+ API for many of the functions in :mod:`Pyjo.Util`. Its counterpart for
31
+ characters is :mod:`Pyjo.String.Unicode`, and both have every method: a
32
+ method that needs characters decodes the bytes with ``UTF-8``, or as the
33
+ characters 0-255 when they are not ``UTF-8``, and encodes the result the
34
+ same way. A method that turns bytes into other bytes returns a
35
+ :mod:`Pyjo.String.Bytes` object, and one that makes characters, like
36
+ :meth:`~Pyjo_String_Bytes.md5_sum`, a :mod:`Pyjo.String.Unicode` object. ::
37
+
38
+ # Use it as bytes
39
+ data = Pyjo.String.Bytes.new(b'foo')
40
+ print(data.upper())
41
+
42
+ See also
43
+ --------
44
+
45
+ :mod:`Pyjoyment`, https://mojolicious.org.
46
+
47
+ Ported from `Mojo::ByteStream <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojo/ByteStream.pm>`_
48
+ of Mojolicious 9.49.
49
+
50
+ Functions
51
+ ---------
52
+ """
53
+
54
+ import Pyjo.Base
55
+ import Pyjo.Collection
56
+ import Pyjo.String.Unicode
57
+ import Pyjo.Util
58
+
59
+ import builtins
60
+ import re
61
+ import sys
62
+
63
+ from collections.abc import Callable
64
+ from typing import IO, Any, Self, cast
65
+
66
+
67
+ type Anything = builtins.object
68
+
69
+
70
+ class Pyjo_String_Bytes(bytes):
71
+ """
72
+ :mod:`Pyjo.String.Bytes` inherits all methods from :class:`bytes` and
73
+ implements the following new ones.
74
+ """
75
+
76
+ def __new__(cls, *parts: Anything) -> Self:
77
+ return super().__new__(cls, b''.join(map(_bytes, parts)))
78
+
79
+ def __repr__(self) -> str:
80
+ return f'{self.__module__}.new({super().__repr__()})'
81
+
82
+ def __str__(self) -> str:
83
+ """::
84
+
85
+ string = str(data)
86
+
87
+ Alias for :meth:`to_str`.
88
+ """
89
+ return self.to_str()
90
+
91
+ # Left out from Mojolicious: the "bool" operator, that makes every
92
+ # bytestream true, as "0" is false in Perl; bytes are false only when empty
93
+
94
+ def b64_decode(self) -> Self:
95
+ """::
96
+
97
+ data = data.b64_decode()
98
+
99
+ Base64 decode bytes with :func:`Pyjo.Util.b64_decode`.
100
+ """
101
+ return self.new(Pyjo.Util.b64_decode(self.to_bytes()))
102
+
103
+ def b64_encode(self, eol: str = '\n') -> 'Pyjo.String.Unicode.object':
104
+ r"""::
105
+
106
+ string = data.b64_encode()
107
+ string = data.b64_encode("\n")
108
+
109
+ Base64 encode bytes with :func:`Pyjo.Util.b64_encode`. ::
110
+
111
+ # "Zm9vIGJhciBiYXo="
112
+ b(b'foo bar baz').b64_encode('')
113
+ """
114
+ return Pyjo.String.Unicode.new(Pyjo.Util.b64_encode(self.to_bytes(), eol))
115
+
116
+ def camelize(self) -> Self:
117
+ """::
118
+
119
+ data = data.camelize()
120
+
121
+ Camelize bytes with :func:`Pyjo.Util.camelize`.
122
+ """
123
+ return self._chars(Pyjo.Util.camelize)
124
+
125
+ def clone(self) -> Self:
126
+ """::
127
+
128
+ data2 = data.clone()
129
+
130
+ Return a new :mod:`Pyjo.String.Bytes` object cloned from these bytes.
131
+ """
132
+ return self.new(self.to_bytes())
133
+
134
+ def decamelize(self) -> Self:
135
+ """::
136
+
137
+ data = data.decamelize()
138
+
139
+ Decamelize bytes with :func:`Pyjo.Util.decamelize`.
140
+ """
141
+ return self._chars(Pyjo.Util.decamelize)
142
+
143
+ def decode(self, encoding: str = 'UTF-8', errors: str = 'strict') -> 'Pyjo.String.Unicode.object':
144
+ """::
145
+
146
+ string = data.decode()
147
+ string = data.decode('iso-8859-1')
148
+
149
+ Decode bytes to a :mod:`Pyjo.String.Unicode` object, defaults to using
150
+ ``UTF-8``. ::
151
+
152
+ # "♥"
153
+ b(b'%E2%99%A5').url_unescape().decode()
154
+ """
155
+ # Unlike Mojolicious: invalid input raises an exception, as bytes.decode()
156
+ # does, and Mojo::ByteStream becomes undef
157
+ return Pyjo.String.Unicode.new(self.to_bytes().decode(encoding, errors))
158
+
159
+ def encode(self, encoding: str = 'UTF-8', errors: str = 'strict') -> Self:
160
+ """::
161
+
162
+ data = data.encode()
163
+ data = data.encode('iso-8859-1')
164
+
165
+ Encode the characters of bytes, defaults to using ``UTF-8``.
166
+ """
167
+ # Unlike Mojolicious: a character that the encoding cannot represent raises
168
+ # an exception, as str.encode() does, and Mojo replaces it
169
+ return self.new(self.to_str().encode(encoding, errors))
170
+
171
+ def gunzip(self) -> Self:
172
+ """::
173
+
174
+ data = data.gunzip()
175
+
176
+ Uncompress bytes with :func:`Pyjo.Util.gunzip`.
177
+ """
178
+ return self.new(Pyjo.Util.gunzip(self.to_bytes()))
179
+
180
+ def gzip(self) -> Self:
181
+ """::
182
+
183
+ data = data.gzip()
184
+
185
+ Compress bytes with :func:`Pyjo.Util.gzip`.
186
+ """
187
+ return self.new(Pyjo.Util.gzip(self.to_bytes()))
188
+
189
+ def hmac_sha1_sum(self, secret: str | bytes) -> 'Pyjo.String.Unicode.object':
190
+ """::
191
+
192
+ string = data.hmac_sha1_sum(b'passw0rd')
193
+
194
+ Generate HMAC-SHA1 checksum for bytes with
195
+ :func:`Pyjo.Util.hmac_sha1_sum`. ::
196
+
197
+ # "7fbdc89263974a89210ea71f171c77d3f8c21471"
198
+ b(b'foo bar baz').hmac_sha1_sum(b'secr3t')
199
+ """
200
+ return Pyjo.String.Unicode.new(Pyjo.Util.hmac_sha1_sum(self.to_bytes(), _bytes(secret)))
201
+
202
+ def html_unescape(self) -> Self:
203
+ """::
204
+
205
+ data = data.html_unescape()
206
+
207
+ Unescape all HTML entities in bytes with :func:`Pyjo.Util.html_unescape`. ::
208
+
209
+ # b"%3Chtml%3E"
210
+ b(b'&lt;html&gt;').html_unescape().url_escape()
211
+ """
212
+ return self._chars(Pyjo.Util.html_unescape)
213
+
214
+ def humanize_bytes(self) -> 'Pyjo.String.Unicode.object':
215
+ """::
216
+
217
+ string = data.humanize_bytes()
218
+
219
+ Turn number of bytes into a simplified human readable format for bytes
220
+ with :func:`Pyjo.Util.humanize_bytes`.
221
+ """
222
+ return Pyjo.String.Unicode.new(self.to_str()).humanize_bytes()
223
+
224
+ def md5_bytes(self) -> Self:
225
+ """::
226
+
227
+ data = data.md5_bytes()
228
+
229
+ Generate binary MD5 checksum for bytes with :func:`Pyjo.Util.md5_bytes`.
230
+ """
231
+ return self.new(Pyjo.Util.md5_bytes(self.to_bytes()))
232
+
233
+ def md5_sum(self) -> 'Pyjo.String.Unicode.object':
234
+ """::
235
+
236
+ string = data.md5_sum()
237
+
238
+ Generate MD5 checksum for bytes with :func:`Pyjo.Util.md5_sum`.
239
+ """
240
+ return Pyjo.String.Unicode.new(Pyjo.Util.md5_sum(self.to_bytes()))
241
+
242
+ @classmethod
243
+ def new(cls, *parts: Anything) -> Self:
244
+ """::
245
+
246
+ data = Pyjo.String.Bytes.new(b'test123')
247
+
248
+ Construct a new :mod:`Pyjo.String.Bytes` object. A :class:`str` is
249
+ encoded with ``UTF-8``.
250
+ """
251
+ return cls(*parts)
252
+
253
+ def punycode_decode(self) -> Self:
254
+ """::
255
+
256
+ data = data.punycode_decode()
257
+
258
+ Punycode decode bytes with :func:`Pyjo.Util.punycode_decode`.
259
+ """
260
+ return self._chars(Pyjo.Util.punycode_decode)
261
+
262
+ def punycode_encode(self) -> Self:
263
+ """::
264
+
265
+ data = data.punycode_encode()
266
+
267
+ Punycode encode bytes with :func:`Pyjo.Util.punycode_encode`.
268
+ """
269
+ return self._chars(Pyjo.Util.punycode_encode)
270
+
271
+ def quote(self) -> Self:
272
+ """::
273
+
274
+ data = data.quote()
275
+
276
+ Quote bytes with :func:`Pyjo.Util.quote`.
277
+ """
278
+ return self.new(Pyjo.Util.quote(self.to_bytes()))
279
+
280
+ def say(self, handle: IO[Any] | None = None) -> Self:
281
+ """::
282
+
283
+ data = data.say()
284
+ data = data.say(sys.stderr)
285
+
286
+ Print bytes to handle and append a newline, defaults to using
287
+ :data:`sys.stdout`.
288
+ """
289
+ text: IO[Any] = handle if handle is not None else sys.stdout
290
+ # A text handle writes bytes to its buffer
291
+ out = cast(IO[bytes], getattr(text, 'buffer', text))
292
+ if out is not text:
293
+ text.flush()
294
+ out.write(self.to_bytes() + b'\n')
295
+ out.flush()
296
+ return self
297
+
298
+ def secure_compare(self, data: str | bytes) -> bool:
299
+ """::
300
+
301
+ boolean = data.secure_compare(data2)
302
+
303
+ Compare bytes with :func:`Pyjo.Util.secure_compare`.
304
+ """
305
+ return Pyjo.Util.secure_compare(self.to_bytes(), data)
306
+
307
+ def sha1_bytes(self) -> Self:
308
+ """::
309
+
310
+ data = data.sha1_bytes()
311
+
312
+ Generate binary SHA1 checksum for bytes with
313
+ :func:`Pyjo.Util.sha1_bytes`.
314
+ """
315
+ return self.new(Pyjo.Util.sha1_bytes(self.to_bytes()))
316
+
317
+ def sha1_sum(self) -> 'Pyjo.String.Unicode.object':
318
+ """::
319
+
320
+ string = data.sha1_sum()
321
+
322
+ Generate SHA1 checksum for bytes with :func:`Pyjo.Util.sha1_sum`.
323
+ """
324
+ return Pyjo.String.Unicode.new(Pyjo.Util.sha1_sum(self.to_bytes()))
325
+
326
+ @property
327
+ def size(self) -> int:
328
+ """::
329
+
330
+ size = data.size
331
+
332
+ Size of bytes.
333
+ """
334
+ return len(self)
335
+
336
+ def slugify(self, allow_unicode: bool = False) -> Self:
337
+ """::
338
+
339
+ data = data.slugify()
340
+ data = data.slugify(boolean)
341
+
342
+ Generate URL slug for bytes with :func:`Pyjo.Util.slugify`.
343
+ """
344
+ return self._chars(lambda string: Pyjo.Util.slugify(string, allow_unicode))
345
+
346
+ # Perl's split, which Mojo uses, is not bytes.split()
347
+ def split( # pyright: ignore[reportIncompatibleMethodOverride]
348
+ self, pattern: str | bytes | re.Pattern[str] | re.Pattern[bytes], limit: int = 0
349
+ ) -> 'Pyjo.Collection.object[Self | None]':
350
+ """::
351
+
352
+ collection = data.split(b',')
353
+ collection = data.split(b',', -1)
354
+
355
+ Turn bytes into :mod:`Pyjo.Collection` object containing
356
+ :mod:`Pyjo.String.Bytes` objects, as
357
+ :meth:`Pyjo.String.Unicode.Pyjo_String_Unicode.split` does. ::
358
+
359
+ # b"One,Two,Three"
360
+ b(b'one,two,three').split(b',').map('camelize').join(',').encode()
361
+ """
362
+ # The bytes are characters 0-255 for the regular expression, as in Perl
363
+ if isinstance(pattern, re.Pattern):
364
+ source = pattern.pattern
365
+ flags = pattern.flags
366
+ if isinstance(source, bytes):
367
+ source, flags = source.decode('latin-1'), flags | re.ASCII
368
+ pattern = re.compile(source, flags)
369
+ elif isinstance(pattern, bytes):
370
+ pattern = pattern.decode('latin-1')
371
+ else:
372
+ pattern = pattern.encode('UTF-8').decode('latin-1')
373
+ fields = Pyjo.String.Unicode.split(pattern, self.to_bytes().decode('latin-1'), limit)
374
+ return Pyjo.Collection.object([None if f is None else self.new(f.encode('latin-1')) for f in fields])
375
+
376
+ def tap(self, cb: Callable[..., Any] | str, *args: Any, **kwargs: Any) -> Self:
377
+ """::
378
+
379
+ data = data.tap(lambda d: ...)
380
+
381
+ Alias for :meth:`Pyjo.Base.tap`.
382
+ """
383
+ Pyjo.Base.tap(self, cb, *args, **kwargs)
384
+ return self
385
+
386
+ def term_escape(self) -> Self:
387
+ """::
388
+
389
+ data = data.term_escape()
390
+
391
+ Escape POSIX control characters in bytes with
392
+ :func:`Pyjo.Util.term_escape`. ::
393
+
394
+ # Print binary checksum to terminal
395
+ b(b'foo').sha1_bytes().term_escape().say()
396
+ """
397
+ return self._chars(Pyjo.Util.term_escape)
398
+
399
+ # Not in Mojolicious: the counterpart of to_str() in Pyjo.String.Mixin
400
+ def to_bytes(self) -> bytes:
401
+ """::
402
+
403
+ data = data.to_bytes()
404
+
405
+ Turn bytes into :class:`bytes`.
406
+ """
407
+ return bytes(self)
408
+
409
+ def to_str(self) -> str:
410
+ """::
411
+
412
+ string = data.to_str()
413
+
414
+ Turn bytes into :class:`str`, decoded with ``UTF-8``, or as the
415
+ characters 0-255 when they are not ``UTF-8``.
416
+ """
417
+ return _decode(self.to_bytes())[0]
418
+
419
+ def trim(self) -> Self:
420
+ """::
421
+
422
+ data = data.trim()
423
+
424
+ Trim whitespace characters from both ends of bytes with
425
+ :func:`Pyjo.Util.trim`.
426
+ """
427
+ return self._chars(Pyjo.Util.trim)
428
+
429
+ def unindent(self) -> Self:
430
+ """::
431
+
432
+ data = data.unindent()
433
+
434
+ Unindent bytes with :func:`Pyjo.Util.unindent`.
435
+ """
436
+ return self._chars(Pyjo.Util.unindent)
437
+
438
+ def unquote(self) -> Self:
439
+ """::
440
+
441
+ data = data.unquote()
442
+
443
+ Unquote bytes with :func:`Pyjo.Util.unquote`.
444
+ """
445
+ return self.new(Pyjo.Util.unquote(self.to_bytes()))
446
+
447
+ def url_escape(self, pattern: bytes | None = None) -> Self:
448
+ r"""::
449
+
450
+ data = data.url_escape()
451
+ data = data.url_escape(rb'^A-Za-z0-9\-._~')
452
+
453
+ Percent encode all unsafe characters in bytes with
454
+ :func:`Pyjo.Util.url_escape`. ::
455
+
456
+ # b"%E2%98%83"
457
+ b('☃').url_escape()
458
+ """
459
+ return self.new(Pyjo.Util.url_escape(self.to_bytes(), pattern))
460
+
461
+ def url_unescape(self) -> Self:
462
+ """::
463
+
464
+ data = data.url_unescape()
465
+
466
+ Decode percent encoded characters in bytes with
467
+ :func:`Pyjo.Util.url_unescape`. ::
468
+
469
+ # b"&lt;html&gt;"
470
+ b(b'%3Chtml%3E').url_unescape().xml_escape()
471
+ """
472
+ return self.new(Pyjo.Util.url_unescape(self.to_bytes()))
473
+
474
+ # Left out from Mojolicious: with_roles, as Pyjoyment has no roles
475
+
476
+ def xml_escape(self) -> Self:
477
+ """::
478
+
479
+ data = data.xml_escape()
480
+
481
+ Escape only the characters ``&``, ``<``, ``>``, ``"`` and ``'`` in
482
+ bytes with :func:`Pyjo.Util.xml_escape`.
483
+ """
484
+ return self._chars(Pyjo.Util.xml_escape)
485
+
486
+ def xor_encode(self, key: str | bytes) -> Self:
487
+ """::
488
+
489
+ data = data.xor_encode(key)
490
+
491
+ XOR encode bytes with :func:`Pyjo.Util.xor_encode`. ::
492
+
493
+ # b"%04%0E%15B%03%1B%10"
494
+ b(b'foo bar').xor_encode(b'baz').url_escape()
495
+ """
496
+ return self.new(Pyjo.Util.xor_encode(self.to_bytes(), _bytes(key)))
497
+
498
+ def _chars(self, func: Callable[[str], str]) -> Self:
499
+ string, encoding = _decode(self.to_bytes())
500
+ result = func(string)
501
+ try:
502
+ return self.new(result.encode(encoding))
503
+ except UnicodeEncodeError:
504
+ return self.new(result.encode('UTF-8'))
505
+
506
+
507
+ def b(*parts: Anything) -> Pyjo_String_Bytes:
508
+ """::
509
+
510
+ data = b(b'test123')
511
+
512
+ Construct a new :mod:`Pyjo.String.Bytes` object.
513
+ """
514
+ return Pyjo_String_Bytes(*parts)
515
+
516
+
517
+ def _bytes(part: Anything) -> bytes:
518
+ if isinstance(part, (bytes, bytearray)):
519
+ return bytes(part)
520
+ return str(part).encode('UTF-8')
521
+
522
+
523
+ def _decode(data: bytes) -> tuple[str, str]:
524
+ try:
525
+ return data.decode('UTF-8'), 'UTF-8'
526
+ except UnicodeDecodeError:
527
+ return data.decode('latin-1'), 'latin-1'
528
+
529
+
530
+ new = Pyjo_String_Bytes.new
531
+ object = Pyjo_String_Bytes
532
+ Bytes = Pyjo_String_Bytes