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/HTML.py ADDED
@@ -0,0 +1,210 @@
1
+ r"""
2
+ Pyjo.String.HTML - String of markup
3
+ ===================================
4
+ ::
5
+
6
+ from Pyjo.String.HTML import html
7
+
8
+ # Markup that is not escaped again
9
+ link = html('<a href="/">Home</a>')
10
+
11
+ # What is added to markup is escaped
12
+ name = '<script>'
13
+ print(html('<p>') + name + html('</p>'))
14
+
15
+ # And what goes into it
16
+ print(html('<p>{}</p>').format(name))
17
+ print(html('<br>').join(['Hello', name]))
18
+
19
+ :mod:`Pyjo.String.HTML` is a :mod:`Pyjo.String.Unicode` that holds markup,
20
+ which escaping leaves as it is: :func:`Pyjo.Util.xml_escape` and anything else
21
+ that knows the ``__html__`` protocol of markupsafe, Jinja and Django. A string
22
+ that is not marked is escaped, a :mod:`Pyjo.String.Unicode` too, so that only
23
+ an explicit :func:`html` turns a string into markup.
24
+
25
+ What is added to markup, with ``+`` on either side, ``%``,
26
+ :meth:`~Pyjo_String_HTML.format`, :meth:`~Pyjo_String_HTML.format_map` or
27
+ :meth:`~Pyjo_String_HTML.join`, is escaped, unless it is markup itself, and
28
+ the result is markup. The methods of :mod:`Pyjo.String.Unicode` return markup
29
+ too, as the string has been marked explicitly; those of :class:`str` return a
30
+ :class:`str`. ::
31
+
32
+ # "&lt;p&gt;"
33
+ html('<p>').xml_escape()
34
+
35
+ See also
36
+ --------
37
+
38
+ :mod:`Pyjoyment`, https://mojolicious.org.
39
+
40
+ Inspired by ``Markup`` of `markupsafe <https://markupsafe.palletsprojects.com/>`_.
41
+
42
+ Functions
43
+ ---------
44
+ """
45
+
46
+ import Pyjo.String.Unicode
47
+ import Pyjo.Util
48
+
49
+ import builtins
50
+ import string
51
+
52
+ from collections.abc import Iterable, Mapping
53
+ from typing import Any, Self, SupportsIndex, cast
54
+
55
+
56
+ type Anything = builtins.object
57
+
58
+
59
+ class Pyjo_String_HTML(Pyjo.String.Unicode.object):
60
+ """
61
+ :mod:`Pyjo.String.HTML` inherits all methods from
62
+ :mod:`Pyjo.String.Unicode` and implements the following new ones.
63
+ """
64
+
65
+ def __add__(self, other: Anything) -> Self:
66
+ """::
67
+
68
+ string = string + other
69
+
70
+ Concatenate, escaping the other string unless it is markup.
71
+ """
72
+ if not isinstance(other, str) and not hasattr(other, '__html__'):
73
+ return NotImplemented
74
+ return self.new(str(self), _escape(other))
75
+
76
+ def __html__(self) -> str:
77
+ """::
78
+
79
+ markup = string.__html__()
80
+
81
+ The markup, as the ``__html__`` protocol gives it.
82
+ """
83
+ return self
84
+
85
+ def __mod__(self, value: Anything) -> Self:
86
+ """::
87
+
88
+ string = string % value
89
+ string = string % (value, value)
90
+ string = string % {'name': value}
91
+
92
+ Format with ``%``, escaping the values unless they are markup or
93
+ numbers.
94
+ """
95
+ if isinstance(value, tuple):
96
+ args: Any = tuple(_Escaped.of(v) for v in cast(tuple[Anything, ...], value))
97
+ elif isinstance(value, Mapping):
98
+ args = {k: _Escaped.of(v) for k, v in cast(Mapping[Anything, Anything], value).items()}
99
+ else:
100
+ args = _Escaped.of(value)
101
+ return self.new(str(self) % args)
102
+
103
+ def __mul__(self, value: SupportsIndex) -> Self:
104
+ """::
105
+
106
+ string = string * 3
107
+
108
+ Repeat the markup.
109
+ """
110
+ return self.new(str(self) * value)
111
+
112
+ def __radd__(self, other: Anything) -> Self:
113
+ """::
114
+
115
+ string = other + string
116
+
117
+ Concatenate, escaping the other string unless it is markup.
118
+ """
119
+ if not isinstance(other, str) and not hasattr(other, '__html__'):
120
+ return NotImplemented
121
+ return self.new(_escape(other), str(self))
122
+
123
+ def __rmul__(self, value: SupportsIndex) -> Self:
124
+ """::
125
+
126
+ string = 3 * string
127
+
128
+ Repeat the markup.
129
+ """
130
+ return self.new(str(self) * value)
131
+
132
+ def format(self, *args: Anything, **kwargs: Anything) -> Self:
133
+ """::
134
+
135
+ string = string.format(value, name=value)
136
+
137
+ Format with :meth:`str.format`, escaping the fields unless they are
138
+ markup.
139
+ """
140
+ return self.new(_FORMATTER.vformat(str(self), args, kwargs))
141
+
142
+ # Any mapping that str.format_map takes, which needs only __getitem__
143
+ def format_map(self, mapping: Any) -> Self:
144
+ """::
145
+
146
+ string = string.format_map({'name': value})
147
+
148
+ Format with :meth:`str.format_map`, escaping the fields unless they
149
+ are markup.
150
+ """
151
+ return self.new(_FORMATTER.vformat(str(self), (), mapping))
152
+
153
+ def join(self, iterable: Iterable[Anything]) -> Self:
154
+ """::
155
+
156
+ string = string.join(['Hello', 'World'])
157
+
158
+ Join the strings with the markup between them, escaping those that
159
+ are not markup.
160
+ """
161
+ return self.new(str(self).join(map(_escape, iterable)))
162
+
163
+
164
+ def html(*parts: Anything) -> Pyjo_String_HTML:
165
+ """::
166
+
167
+ string = html('<p>Hello</p>')
168
+
169
+ Construct a new :mod:`Pyjo.String.HTML` object, marking the string as
170
+ markup.
171
+ """
172
+ return Pyjo_String_HTML(*parts)
173
+
174
+
175
+ # A value of the formatting with %, which gives the escaped string, as %s and %r take it; numbers go as they are
176
+ class _Escaped:
177
+ def __init__(self, value: Anything) -> None:
178
+ self.value = value
179
+
180
+ def __repr__(self) -> str:
181
+ return _escape(repr(self.value))
182
+
183
+ def __str__(self) -> str:
184
+ return _escape(self.value)
185
+
186
+ @classmethod
187
+ def of(cls, value: Anything) -> Anything:
188
+ return value if isinstance(value, (int, float)) else cls(value)
189
+
190
+
191
+ # The formatting of str.format, which escapes the fields that are not markup after their conversion and format
192
+ class _Formatter(string.Formatter):
193
+ def format_field(self, value: Any, format_spec: str) -> str:
194
+ if not format_spec and hasattr(value, '__html__'):
195
+ return value.__html__()
196
+ return _escape(format(value, format_spec))
197
+
198
+
199
+ _FORMATTER = _Formatter()
200
+
201
+
202
+ def _escape(value: Anything) -> str:
203
+ if (markup := getattr(value, '__html__', None)) is not None:
204
+ return markup()
205
+ return Pyjo.Util.xml_escape(str(value))
206
+
207
+
208
+ new = Pyjo_String_HTML.new
209
+ object = Pyjo_String_HTML
210
+ HTML = Pyjo_String_HTML
Pyjo/String/Mixin.py ADDED
@@ -0,0 +1,333 @@
1
+ """
2
+ Pyjo.String.Mixin - Object with to_bytes/to_str methods
3
+ =======================================================
4
+ ::
5
+
6
+ import Pyjo.Base
7
+
8
+ from Pyjo.String.Mixin import Mixin
9
+
10
+ class SubClass(Pyjo.Base.object, Mixin):
11
+ def to_bytes(self):
12
+ return b'value'
13
+
14
+ def to_str(self):
15
+ return 'value'
16
+
17
+ # Use it as a string
18
+ obj = SubClass()
19
+ print(f'{obj:>10}')
20
+ print(obj + '!')
21
+
22
+ # Or import the module, as in Google Python Style Guide
23
+
24
+ import Pyjo.Base
25
+ import Pyjo.String.Mixin
26
+
27
+ class SubClass(Pyjo.Base.object, Pyjo.String.Mixin.object):
28
+ def to_bytes(self):
29
+ return b'value'
30
+
31
+ def to_str(self):
32
+ return 'value'
33
+
34
+ # Use it as a string
35
+ obj = SubClass.new()
36
+ print(f'{obj:>10}')
37
+ print(obj + '!')
38
+
39
+ :mod:`Pyjo.String.Mixin` is the mixin class for objects with a
40
+ :meth:`to_str` and/or a :meth:`to_bytes` method, which turns them into strings
41
+ wherever Python converts, compares or concatenates them, as Perl does with the
42
+ overloaded ``""`` of Mojo's objects. The string form is the one of
43
+ :meth:`to_str`, or of :meth:`to_bytes` for an object that has only it.
44
+
45
+ A class that mixes it in overrides a conversion where its value means
46
+ something else than its string form, as :mod:`Pyjo.Date` does with
47
+ :meth:`~Pyjo_String_Mixin.__float__`, or where it is a container of its own,
48
+ as :mod:`Pyjo.Path` is a sequence of its parts: the mixin leaves out
49
+ ``__len__``, ``__iter__`` and ``__contains__``, which would make every
50
+ object a sequence of characters.
51
+
52
+ The object is not a :class:`str`, so a function that takes only an instance
53
+ of it, like :meth:`str.join` or :func:`urllib.parse.quote`, gets
54
+ ``str(obj)``. ::
55
+
56
+ # 'value/value'
57
+ '/'.join(str(obj) for obj in (SubClass.new(), SubClass.new()))
58
+
59
+ See also
60
+ --------
61
+
62
+ :mod:`Pyjoyment`, https://mojolicious.org.
63
+
64
+ Classes
65
+ -------
66
+ """
67
+
68
+ import Pyjo.Base
69
+ import Pyjo.String.Bytes
70
+ import Pyjo.String.Unicode
71
+
72
+ import builtins
73
+ import math
74
+
75
+ from typing import Any
76
+
77
+
78
+ type Anything = builtins.object
79
+
80
+
81
+ class Pyjo_String_Mixin:
82
+ """
83
+ This mixin does not provide own constructor method
84
+ and implements the following new methods.
85
+ """
86
+
87
+ def __add__(self, other: Anything) -> 'Pyjo.String.Unicode.object | Pyjo.String.Bytes.object':
88
+ """::
89
+
90
+ string = obj + 'string'
91
+
92
+ Concatenate the string form of the object with another string, as a
93
+ :mod:`Pyjo.String.Unicode` object, or a :mod:`Pyjo.String.Bytes` object
94
+ for bytes.
95
+ """
96
+ if (result := _concat(_string(self), other)) is None:
97
+ return NotImplemented
98
+ return result
99
+
100
+ def __bool__(self) -> bool:
101
+ """::
102
+
103
+ boolean = bool(obj)
104
+
105
+ True if the string form is not empty.
106
+ """
107
+ return bool(_string(self))
108
+
109
+ def __bytes__(self) -> bytes:
110
+ """::
111
+
112
+ bstring = bytes(obj)
113
+
114
+ Bytes of the object, :meth:`to_bytes`, or :meth:`to_str` encoded with
115
+ ``UTF-8``.
116
+ """
117
+ if (to_bytes := getattr(self, 'to_bytes', None)) is not None:
118
+ return bytes(to_bytes())
119
+ string = _string(self)
120
+ return string.encode() if isinstance(string, str) else string
121
+
122
+ def __ceil__(self) -> int:
123
+ """::
124
+
125
+ number = math.ceil(obj)
126
+
127
+ The smallest integer that is not less than ``float(obj)``.
128
+ """
129
+ return math.ceil(float(self))
130
+
131
+ def __complex__(self) -> complex:
132
+ """::
133
+
134
+ number = complex(obj)
135
+
136
+ Convert the string form into a complex number.
137
+ """
138
+ string = _string(self)
139
+ return complex(string.decode() if isinstance(string, bytes) else string)
140
+
141
+ def __eq__(self, other: Anything) -> bool:
142
+ """::
143
+
144
+ boolean = obj == other
145
+
146
+ True if the string form of the object is equal to the other value.
147
+ """
148
+ return _string(self) == other
149
+
150
+ def __float__(self) -> float:
151
+ """::
152
+
153
+ number = float(obj)
154
+
155
+ Convert the string form into a float number.
156
+ """
157
+ return float(_string(self))
158
+
159
+ def __floor__(self) -> int:
160
+ """::
161
+
162
+ number = math.floor(obj)
163
+
164
+ The largest integer that is not greater than ``float(obj)``.
165
+ """
166
+ return math.floor(float(self))
167
+
168
+ def __format__(self, format_spec: str) -> str:
169
+ """::
170
+
171
+ string = format(obj, '>10')
172
+ string = f'{obj:>10}'
173
+
174
+ Format the string form, ``str(obj)``, as :func:`format` formats a
175
+ :class:`str`.
176
+ """
177
+ return format(str(self), format_spec)
178
+
179
+ def __ge__(self, other: Anything) -> bool:
180
+ """::
181
+
182
+ boolean = obj >= other
183
+
184
+ True if the string form of the object is equal to or greater than the
185
+ other value.
186
+ """
187
+ return _cmp(self) >= other
188
+
189
+ def __gt__(self, other: Anything) -> bool:
190
+ """::
191
+
192
+ boolean = obj > other
193
+
194
+ True if the string form of the object is greater than the other value.
195
+ """
196
+ return _cmp(self) > other
197
+
198
+ def __hash__(self) -> int:
199
+ """::
200
+
201
+ number = hash(obj)
202
+
203
+ Hash of the string form, so that the object and its string are the
204
+ same key of a :class:`dict`.
205
+ """
206
+ return hash(_string(self))
207
+
208
+ def __int__(self) -> int:
209
+ """::
210
+
211
+ number = int(obj)
212
+
213
+ Convert the string form into an integer number.
214
+ """
215
+ return int(_string(self))
216
+
217
+ def __le__(self, other: Anything) -> bool:
218
+ """::
219
+
220
+ boolean = obj <= other
221
+
222
+ True if the string form of the object is equal to or less than the
223
+ other value.
224
+ """
225
+ return _cmp(self) <= other
226
+
227
+ def __lt__(self, other: Anything) -> bool:
228
+ """::
229
+
230
+ boolean = obj < other
231
+
232
+ True if the string form of the object is less than the other value.
233
+ """
234
+ return _cmp(self) < other
235
+
236
+ def __ne__(self, other: Anything) -> bool:
237
+ """::
238
+
239
+ boolean = obj != other
240
+
241
+ True if the string form of the object is not equal to the other value.
242
+ """
243
+ return _string(self) != other
244
+
245
+ def __radd__(self, other: Anything) -> 'Pyjo.String.Unicode.object | Pyjo.String.Bytes.object':
246
+ """::
247
+
248
+ string = 'string' + obj
249
+
250
+ Concatenate another string with the string form of the object, as a
251
+ :mod:`Pyjo.String.Unicode` object, or a :mod:`Pyjo.String.Bytes` object
252
+ for bytes.
253
+ """
254
+ string = _string(self)
255
+ if not isinstance(other, type(string)) or (result := _concat(other, string)) is None:
256
+ return NotImplemented
257
+ return result
258
+
259
+ def __repr__(self) -> str:
260
+ """::
261
+
262
+ string = repr(obj)
263
+
264
+ Representation of the object, with its string form:
265
+ ``Pyjo.URL.new('http://example.com')``.
266
+ """
267
+ string = str(self) if getattr(self, 'to_str', None) is not None else bytes(self)
268
+ if self.__module__ == '__main__':
269
+ return f'{self.__class__.__name__}({string!r})'
270
+ if isinstance(self, Pyjo.Base.object):
271
+ return f'{self.__module__}.new({string!r})'
272
+ return f'{self.__module__}.{self.__class__.__name__}({string!r})'
273
+
274
+ def __round__(self, ndigits: int | None = None) -> int | float:
275
+ """::
276
+
277
+ number = round(obj)
278
+ number = round(obj, 2)
279
+
280
+ ``float(obj)`` rounded, to an integer without ``ndigits``.
281
+ """
282
+ return round(float(self), ndigits)
283
+
284
+ def __str__(self) -> str:
285
+ """::
286
+
287
+ string = str(obj)
288
+
289
+ String form of the object, :meth:`to_str`, or the representation of
290
+ the bytes of :meth:`to_bytes`, as ``str(b'value')`` gives it.
291
+ """
292
+ string = _string(self)
293
+ return string if isinstance(string, str) else repr(string)
294
+
295
+ def __trunc__(self) -> int:
296
+ """::
297
+
298
+ number = math.trunc(obj)
299
+
300
+ ``float(obj)`` without its fraction.
301
+ """
302
+ return math.trunc(float(self))
303
+
304
+
305
+ # The string form: what to_str or to_bytes gives
306
+ def _string(obj: Anything) -> str | bytes:
307
+ if (to_str := getattr(obj, 'to_str', None)) is not None:
308
+ return str(to_str())
309
+ if (to_bytes := getattr(obj, 'to_bytes', None)) is not None:
310
+ return to_bytes()
311
+ raise NotImplementedError('Method "to_bytes" or "to_str" not implemented by subclass')
312
+
313
+
314
+ # The string form for a comparison, which raises TypeError for another type, as the str or bytes does
315
+ def _cmp(obj: Anything) -> Any:
316
+ return _string(obj)
317
+
318
+
319
+ # The concatenation of strings of the same type, None for another type
320
+ def _concat(string: str | bytes, other: Anything) -> 'Pyjo.String.Unicode.object | Pyjo.String.Bytes.object | None':
321
+ if isinstance(other, Pyjo_String_Mixin):
322
+ other = _string(other)
323
+ if isinstance(string, str):
324
+ if not isinstance(other, str):
325
+ return None
326
+ return Pyjo.String.Unicode.new(string + other)
327
+ if not isinstance(other, bytes | bytearray):
328
+ return None
329
+ return Pyjo.String.Bytes.new(string + other)
330
+
331
+
332
+ object = Pyjo_String_Mixin
333
+ Mixin = Pyjo_String_Mixin