Pyjoyment 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Pyjo/App/ASGI.py +735 -0
- Pyjo/App/CGI.py +773 -0
- Pyjo/App/FastCGI.py +631 -0
- Pyjo/App/Lambda.py +987 -0
- Pyjo/App/WSGI.py +427 -0
- Pyjo/App/__init__.py +409 -0
- Pyjo/Asset/File.py +377 -0
- Pyjo/Asset/Memory.py +235 -0
- Pyjo/Asset/__init__.py +200 -0
- Pyjo/Base.py +215 -0
- Pyjo/Cache.py +119 -0
- Pyjo/Collection.py +570 -0
- Pyjo/Content/MultiPart.py +325 -0
- Pyjo/Content/Single.py +193 -0
- Pyjo/Content/__init__.py +806 -0
- Pyjo/Cookie/Request.py +90 -0
- Pyjo/Cookie/Response.py +294 -0
- Pyjo/Cookie/__init__.py +143 -0
- Pyjo/DOM/CSS.py +1019 -0
- Pyjo/DOM/HTML.py +550 -0
- Pyjo/DOM/__init__.py +1329 -0
- Pyjo/Date.py +294 -0
- Pyjo/EventEmitter.py +522 -0
- Pyjo/Exception.py +494 -0
- Pyjo/File.py +959 -0
- Pyjo/GetOpt.py +605 -0
- Pyjo/Headers.py +760 -0
- Pyjo/HelloWorld.py +77 -0
- Pyjo/Home.py +109 -0
- Pyjo/IOLoop/ChildProcess.py +591 -0
- Pyjo/IOLoop/Client.py +736 -0
- Pyjo/IOLoop/Datagram.py +982 -0
- Pyjo/IOLoop/Messages.py +664 -0
- Pyjo/IOLoop/Server.py +458 -0
- Pyjo/IOLoop/Stdio.py +446 -0
- Pyjo/IOLoop/Stream.py +644 -0
- Pyjo/IOLoop/Subprocess.py +419 -0
- Pyjo/IOLoop/TLS.py +360 -0
- Pyjo/IOLoop/__init__.py +1036 -0
- Pyjo/IOLoop/certs/README.md +41 -0
- Pyjo/IOLoop/certs/ca.crt +20 -0
- Pyjo/IOLoop/certs/server.crt +21 -0
- Pyjo/IOLoop/certs/server.key +28 -0
- Pyjo/JSON/Pointer.py +135 -0
- Pyjo/JSON/RPC.py +772 -0
- Pyjo/JSON/Schema.py +2506 -0
- Pyjo/JSON/__init__.py +573 -0
- Pyjo/Loader.py +342 -0
- Pyjo/Log.py +723 -0
- Pyjo/Message/Request.py +725 -0
- Pyjo/Message/Response.py +476 -0
- Pyjo/Message/__init__.py +830 -0
- Pyjo/Parameters.py +472 -0
- Pyjo/Path.py +419 -0
- Pyjo/Promise.py +894 -0
- Pyjo/Prove.py +1305 -0
- Pyjo/Reactor/Asyncio.py +854 -0
- Pyjo/Reactor/Poll.py +439 -0
- Pyjo/Reactor/__init__.py +525 -0
- Pyjo/SSE.py +119 -0
- Pyjo/Server/ASGI.py +486 -0
- Pyjo/Server/CGI.py +259 -0
- Pyjo/Server/Daemon.py +1007 -0
- Pyjo/Server/FastCGI.py +517 -0
- Pyjo/Server/Hot/__init__.py +687 -0
- Pyjo/Server/Hot/__main__.py +5 -0
- Pyjo/Server/Lambda.py +641 -0
- Pyjo/Server/Prefork.py +917 -0
- Pyjo/Server/Prethread.py +394 -0
- Pyjo/Server/Reload/Backend/Poll.py +114 -0
- Pyjo/Server/Reload/Backend/__init__.py +126 -0
- Pyjo/Server/Reload/__init__.py +482 -0
- Pyjo/Server/Reload/__main__.py +5 -0
- Pyjo/Server/Stdio.py +228 -0
- Pyjo/Server/WSGI.py +349 -0
- Pyjo/Server/__init__.py +396 -0
- Pyjo/String/Bytes.py +532 -0
- Pyjo/String/HTML.py +210 -0
- Pyjo/String/Mixin.py +333 -0
- Pyjo/String/Template.py +470 -0
- Pyjo/String/Unicode.py +553 -0
- Pyjo/String/__init__.py +0 -0
- Pyjo/TOML.py +232 -0
- Pyjo/Template.py +1290 -0
- Pyjo/Test/Pyjo.py +1454 -0
- Pyjo/Test/__init__.py +1233 -0
- Pyjo/Test/pytest_plugin.py +305 -0
- Pyjo/Transaction/HTTP.py +374 -0
- Pyjo/Transaction/WebSocket.py +709 -0
- Pyjo/Transaction/__init__.py +429 -0
- Pyjo/URL/Template.py +459 -0
- Pyjo/URL/__init__.py +651 -0
- Pyjo/Upload.py +139 -0
- Pyjo/UserAgent/CookieJar.py +391 -0
- Pyjo/UserAgent/Proxy.py +138 -0
- Pyjo/UserAgent/Server.py +239 -0
- Pyjo/UserAgent/Transactor.py +766 -0
- Pyjo/UserAgent/__init__.py +1243 -0
- Pyjo/Util.py +3567 -0
- Pyjo/WebSocket.py +332 -0
- Pyjo/YAML.py +1167 -0
- Pyjo/__init__.py +441 -0
- Pyjo/__main__.py +35 -0
- Pyjo/py.typed +0 -0
- Pyjoyment/Command/Author/__init__.py +20 -0
- Pyjoyment/Command/Author/generate/__init__.py +106 -0
- Pyjoyment/Command/Author/generate/app.py +299 -0
- Pyjoyment/Command/Author/generate/dockerfile.py +281 -0
- Pyjoyment/Command/Author/generate/kubernetes.py +514 -0
- Pyjoyment/Command/Author/generate/lambda_zip.py +372 -0
- Pyjoyment/Command/Author/generate/lite_app.py +113 -0
- Pyjoyment/Command/Author/generate/plugin.py +267 -0
- Pyjoyment/Command/Author/generate/pyproject.py +123 -0
- Pyjoyment/Command/Author/inflate.py +101 -0
- Pyjoyment/Command/__init__.py +332 -0
- Pyjoyment/Command/asgi.py +92 -0
- Pyjoyment/Command/cgi.py +90 -0
- Pyjoyment/Command/daemon.py +160 -0
- Pyjoyment/Command/eval.py +128 -0
- Pyjoyment/Command/fastcgi.py +99 -0
- Pyjoyment/Command/get.py +305 -0
- Pyjoyment/Command/lambda.py +117 -0
- Pyjoyment/Command/prefork.py +181 -0
- Pyjoyment/Command/prethread.py +126 -0
- Pyjoyment/Command/routes.py +133 -0
- Pyjoyment/Command/stdio.py +92 -0
- Pyjoyment/Command/version.py +141 -0
- Pyjoyment/Command/wsgi.py +93 -0
- Pyjoyment/Commands.py +546 -0
- Pyjoyment/Controller.py +1307 -0
- Pyjoyment/HelloWorld.py +56 -0
- Pyjoyment/Lite.py +494 -0
- Pyjoyment/Plugin/AllowedHosts.py +205 -0
- Pyjoyment/Plugin/Config.py +248 -0
- Pyjoyment/Plugin/DefaultHelpers.py +1202 -0
- Pyjoyment/Plugin/EPLRenderer.py +134 -0
- Pyjoyment/Plugin/EPRenderer.py +212 -0
- Pyjoyment/Plugin/HeaderCondition.py +98 -0
- Pyjoyment/Plugin/Health.py +325 -0
- Pyjoyment/Plugin/JSONConfig.py +172 -0
- Pyjoyment/Plugin/Mount.py +223 -0
- Pyjoyment/Plugin/PyRenderer.py +209 -0
- Pyjoyment/Plugin/TOMLConfig.py +141 -0
- Pyjoyment/Plugin/TagHelpers.py +959 -0
- Pyjoyment/Plugin/YAMLConfig.py +178 -0
- Pyjoyment/Plugin/__init__.py +80 -0
- Pyjoyment/Plugins.py +215 -0
- Pyjoyment/Renderer.py +673 -0
- Pyjoyment/Routes/Match.py +251 -0
- Pyjoyment/Routes/Pattern.py +443 -0
- Pyjoyment/Routes/Route.py +827 -0
- Pyjoyment/Routes/__init__.py +419 -0
- Pyjoyment/Sessions.py +255 -0
- Pyjoyment/Static.py +421 -0
- Pyjoyment/Types.py +238 -0
- Pyjoyment/Validator/Validation.py +395 -0
- Pyjoyment/Validator/__init__.py +304 -0
- Pyjoyment/__init__.py +1083 -0
- Pyjoyment/__main__.py +5 -0
- Pyjoyment/py.typed +0 -0
- Pyjoyment/resources/public/favicon.ico +0 -0
- Pyjoyment/resources/public/favicon.svg +345 -0
- Pyjoyment/resources/public/pyjo/bootstrap/LICENSE +21 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.bundle.min.js.map +1 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.css +6 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.js +7 -0
- Pyjoyment/resources/public/pyjo/bootstrap/bootstrap.min.css.map +1 -0
- Pyjoyment/resources/public/pyjo/failunicat.png +0 -0
- Pyjoyment/resources/public/pyjo/failunicat.svg +50 -0
- Pyjoyment/resources/public/pyjo/highlight.js/LICENSE +29 -0
- Pyjoyment/resources/public/pyjo/highlight.js/highlight-mojo-dark.css +56 -0
- Pyjoyment/resources/public/pyjo/highlight.js/highlight.min.js +1262 -0
- Pyjoyment/resources/public/pyjo/highlight.js/pyjoyment.min.js +1 -0
- Pyjoyment/resources/public/pyjo/logo-black-4x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-black-4x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white-2x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white-2x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white-4x.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white-4x.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo-white.png +0 -0
- Pyjoyment/resources/public/pyjo/logo-white.svg +346 -0
- Pyjoyment/resources/public/pyjo/logo.png +0 -0
- Pyjoyment/resources/public/pyjo/logo.svg +346 -0
- Pyjoyment/resources/public/pyjo/notfound.png +0 -0
- Pyjoyment/resources/public/pyjo/notfound.svg +3 -0
- Pyjoyment/resources/public/pyjo/nounicat.png +0 -0
- Pyjoyment/resources/public/pyjo/nounicat.svg +5 -0
- Pyjoyment/resources/public/pyjo/pinstripe-dark.png +0 -0
- Pyjoyment/resources/public/pyjo/pinstripe-dark.svg +4 -0
- Pyjoyment/resources/public/pyjo/pinstripe-light.png +0 -0
- Pyjoyment/resources/public/pyjo/pinstripe-light.svg +4 -0
- Pyjoyment/resources/public/pyjo/pyjo.css +204 -0
- Pyjoyment/resources/templates/pyjo/debug.html.ep +346 -0
- Pyjoyment/resources/templates/pyjo/exception.html.ep +32 -0
- Pyjoyment/resources/templates/pyjo/not_found.html.ep +45 -0
- pyjoyment-0.1.0.dist-info/METADATA +376 -0
- pyjoyment-0.1.0.dist-info/RECORD +200 -0
- pyjoyment-0.1.0.dist-info/WHEEL +4 -0
- pyjoyment-0.1.0.dist-info/entry_points.txt +8 -0
- pyjoyment-0.1.0.dist-info/licenses/LICENSE +201 -0
Pyjo/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
|
+
# "<p>"
|
|
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
|