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/Parameters.py
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pyjo.Parameters - Parameters
|
|
3
|
+
============================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
from Pyjo.Parameters import Parameters
|
|
7
|
+
|
|
8
|
+
# Parse
|
|
9
|
+
params = Parameters('foo=bar&baz=23')
|
|
10
|
+
print(params.param('baz'))
|
|
11
|
+
|
|
12
|
+
# Or import the module, as in Google Python Style Guide
|
|
13
|
+
|
|
14
|
+
import Pyjo.Parameters
|
|
15
|
+
|
|
16
|
+
# Parse
|
|
17
|
+
params = Pyjo.Parameters.new('foo=bar&baz=23')
|
|
18
|
+
print(params.param('baz'))
|
|
19
|
+
|
|
20
|
+
# Build
|
|
21
|
+
params = Pyjo.Parameters.new('foo', 'bar', 'baz', 23)
|
|
22
|
+
params.pairs.append(('i', '♥ pyjoyment'))
|
|
23
|
+
print(params)
|
|
24
|
+
|
|
25
|
+
:mod:`Pyjo.Parameters` is a container for form parameters used by
|
|
26
|
+
:mod:`Pyjo.URL`, based on :rfc:`3986` and the
|
|
27
|
+
`HTML Living Standard <https://html.spec.whatwg.org>`_.
|
|
28
|
+
|
|
29
|
+
The parameters are pairs of a name and a value, as tuples. Methods that take
|
|
30
|
+
parameters take them as tuples, as names followed by their values, or as
|
|
31
|
+
keyword arguments: ::
|
|
32
|
+
|
|
33
|
+
params.append(('foo', 'bar'), ('baz', 23))
|
|
34
|
+
params.append('foo', 'bar', 'baz', 23)
|
|
35
|
+
params.append(foo='bar', baz=23)
|
|
36
|
+
|
|
37
|
+
See also
|
|
38
|
+
--------
|
|
39
|
+
|
|
40
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
41
|
+
|
|
42
|
+
Ported from `Mojo::Parameters <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojo/Parameters.pm>`_
|
|
43
|
+
of Mojolicious 9.49.
|
|
44
|
+
|
|
45
|
+
Classes
|
|
46
|
+
-------
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
import Pyjo.Base
|
|
50
|
+
import Pyjo.String.Mixin
|
|
51
|
+
|
|
52
|
+
from Pyjo.Util import decode, url_escape, url_unescape
|
|
53
|
+
|
|
54
|
+
import builtins
|
|
55
|
+
import re
|
|
56
|
+
|
|
57
|
+
from collections.abc import Iterator
|
|
58
|
+
from typing import Self, cast, overload
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# The module ends with `object = Pyjo_Parameters`, which an annotation of
|
|
62
|
+
# `object` would mean, as annotations are evaluated lazily
|
|
63
|
+
type Anything = builtins.object
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Pyjo_Parameters(Pyjo.Base.object, Pyjo.String.Mixin.object):
|
|
67
|
+
"""
|
|
68
|
+
:mod:`Pyjo.Parameters` inherits all methods from :mod:`Pyjo.Base` and
|
|
69
|
+
:mod:`Pyjo.String.Mixin` and implements the following new ones.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(self, *args: Anything, **kwargs: Anything) -> None:
|
|
73
|
+
"""::
|
|
74
|
+
|
|
75
|
+
params = Pyjo.Parameters.new()
|
|
76
|
+
params = Pyjo.Parameters.new('foo=b%3Bar&baz=23')
|
|
77
|
+
params = Pyjo.Parameters.new('foo', 'b&ar')
|
|
78
|
+
params = Pyjo.Parameters.new('foo', ['ba&r', 'baz'])
|
|
79
|
+
params = Pyjo.Parameters.new('foo', ['bar', 'baz'], 'bar', 23)
|
|
80
|
+
params = Pyjo.Parameters.new(foo=['bar', 'baz'], bar=23)
|
|
81
|
+
|
|
82
|
+
Construct a new :mod:`Pyjo.Parameters` object and :meth:`parse` parameters
|
|
83
|
+
if necessary.
|
|
84
|
+
"""
|
|
85
|
+
self.charset: str | None = 'UTF-8'
|
|
86
|
+
"""::
|
|
87
|
+
|
|
88
|
+
charset = params.charset
|
|
89
|
+
params.charset = 'UTF-8'
|
|
90
|
+
|
|
91
|
+
Charset used for encoding and decoding parameters, defaults to ``UTF-8``. ::
|
|
92
|
+
|
|
93
|
+
# Disable encoding and decoding
|
|
94
|
+
params.charset = None
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
self._pairs: list[tuple[str, str]] | None = None
|
|
98
|
+
self._string: str | bytes | None = None
|
|
99
|
+
|
|
100
|
+
if args or kwargs:
|
|
101
|
+
self.parse(*args, **kwargs)
|
|
102
|
+
|
|
103
|
+
def __bool__(self) -> bool:
|
|
104
|
+
"""::
|
|
105
|
+
|
|
106
|
+
boolean = bool(params)
|
|
107
|
+
|
|
108
|
+
Always true.
|
|
109
|
+
"""
|
|
110
|
+
return True
|
|
111
|
+
|
|
112
|
+
def __getitem__(self, index: int) -> tuple[str, str]:
|
|
113
|
+
"""::
|
|
114
|
+
|
|
115
|
+
pair = params[0]
|
|
116
|
+
|
|
117
|
+
Alias for :attr:`pairs`. Note that this will normalize the parameters. ::
|
|
118
|
+
|
|
119
|
+
print(params[0])
|
|
120
|
+
"""
|
|
121
|
+
return self.pairs[index]
|
|
122
|
+
|
|
123
|
+
def __iter__(self) -> Iterator[tuple[str, str]]:
|
|
124
|
+
"""::
|
|
125
|
+
|
|
126
|
+
pairs = list(params)
|
|
127
|
+
|
|
128
|
+
Alias for :attr:`pairs`. Note that this will normalize the parameters. ::
|
|
129
|
+
|
|
130
|
+
for name, value in params:
|
|
131
|
+
print(name, value)
|
|
132
|
+
"""
|
|
133
|
+
return iter(self.pairs)
|
|
134
|
+
|
|
135
|
+
def __len__(self) -> int:
|
|
136
|
+
"""::
|
|
137
|
+
|
|
138
|
+
size = len(params)
|
|
139
|
+
|
|
140
|
+
Alias for :attr:`pairs`. Note that this will normalize the parameters.
|
|
141
|
+
"""
|
|
142
|
+
return len(self.pairs)
|
|
143
|
+
|
|
144
|
+
def __str__(self) -> str:
|
|
145
|
+
"""::
|
|
146
|
+
|
|
147
|
+
string = str(params)
|
|
148
|
+
|
|
149
|
+
Alias for :meth:`to_str`.
|
|
150
|
+
"""
|
|
151
|
+
return self.to_str()
|
|
152
|
+
|
|
153
|
+
def append(self, *args: Anything, **kwargs: Anything) -> Self:
|
|
154
|
+
"""::
|
|
155
|
+
|
|
156
|
+
params = params.append('foo', 'ba&r')
|
|
157
|
+
params = params.append('foo', ['ba&r', 'baz'])
|
|
158
|
+
params = params.append('foo', ['bar', 'baz'], 'bar', 23)
|
|
159
|
+
params = params.append(Pyjo.Parameters.new())
|
|
160
|
+
|
|
161
|
+
Append parameters. Note that this method will normalize the parameters. ::
|
|
162
|
+
|
|
163
|
+
# "foo=bar&foo=baz"
|
|
164
|
+
Pyjo.Parameters.new('foo=bar').append(Pyjo.Parameters.new('foo=baz'))
|
|
165
|
+
|
|
166
|
+
# "foo=bar&foo=baz"
|
|
167
|
+
Pyjo.Parameters.new('foo=bar').append('foo', 'baz')
|
|
168
|
+
|
|
169
|
+
# "foo=bar&foo=baz&foo=yada"
|
|
170
|
+
Pyjo.Parameters.new('foo=bar').append('foo', ['baz', 'yada'])
|
|
171
|
+
|
|
172
|
+
# "foo=bar&foo=baz&foo=yada&bar=23"
|
|
173
|
+
Pyjo.Parameters.new('foo=bar').append('foo', ['baz', 'yada'], 'bar', 23)
|
|
174
|
+
"""
|
|
175
|
+
old = self.pairs
|
|
176
|
+
for name, value in _pairs(args, kwargs):
|
|
177
|
+
# Multiple values
|
|
178
|
+
if isinstance(value, (list, tuple)):
|
|
179
|
+
old.extend((name, '' if v is None else _str(v)) for v in cast(list[Anything], value))
|
|
180
|
+
|
|
181
|
+
# Single value
|
|
182
|
+
elif value is not None:
|
|
183
|
+
old.append((name, _str(value)))
|
|
184
|
+
|
|
185
|
+
return self
|
|
186
|
+
|
|
187
|
+
def clone(self) -> Self:
|
|
188
|
+
"""::
|
|
189
|
+
|
|
190
|
+
params2 = params.clone()
|
|
191
|
+
|
|
192
|
+
Return a new :mod:`Pyjo.Parameters` object cloned from these parameters.
|
|
193
|
+
"""
|
|
194
|
+
clone = self.new()
|
|
195
|
+
clone.charset = self.charset
|
|
196
|
+
if self._string is not None:
|
|
197
|
+
clone._string = self._string
|
|
198
|
+
else:
|
|
199
|
+
clone._pairs = list(self.pairs)
|
|
200
|
+
return clone
|
|
201
|
+
|
|
202
|
+
def every_param(self, name: Anything) -> list[str]:
|
|
203
|
+
"""::
|
|
204
|
+
|
|
205
|
+
values = params.every_param('foo')
|
|
206
|
+
|
|
207
|
+
Similar to :meth:`param`, but returns all values sharing the same name as a
|
|
208
|
+
list. Note that this method will normalize the parameters. ::
|
|
209
|
+
|
|
210
|
+
# Get first value
|
|
211
|
+
print(params.every_param('foo')[0])
|
|
212
|
+
"""
|
|
213
|
+
name = str(name)
|
|
214
|
+
return [v for n, v in self.pairs if n == name]
|
|
215
|
+
|
|
216
|
+
def merge(self, *args: Anything, **kwargs: Anything) -> Self:
|
|
217
|
+
"""::
|
|
218
|
+
|
|
219
|
+
params = params.merge('foo', 'ba&r')
|
|
220
|
+
params = params.merge('foo', ['ba&r', 'baz'])
|
|
221
|
+
params = params.merge('foo', ['bar', 'baz'], 'bar', 23)
|
|
222
|
+
params = params.merge(Pyjo.Parameters.new())
|
|
223
|
+
|
|
224
|
+
Merge parameters. Note that this method will normalize the parameters. ::
|
|
225
|
+
|
|
226
|
+
# "foo=baz"
|
|
227
|
+
Pyjo.Parameters.new('foo=bar').merge(Pyjo.Parameters.new('foo=baz'))
|
|
228
|
+
|
|
229
|
+
# "yada=yada&foo=baz"
|
|
230
|
+
Pyjo.Parameters.new('foo=bar&yada=yada').merge('foo', 'baz')
|
|
231
|
+
|
|
232
|
+
# "yada=yada"
|
|
233
|
+
Pyjo.Parameters.new('foo=bar&yada=yada').merge('foo', None)
|
|
234
|
+
"""
|
|
235
|
+
if len(args) == 1 and not kwargs and isinstance(args[0], Pyjo_Parameters):
|
|
236
|
+
merge: dict[str, Anything] = {**args[0].to_dict()}
|
|
237
|
+
else:
|
|
238
|
+
merge = dict(_pairs(args, kwargs))
|
|
239
|
+
|
|
240
|
+
for name in sorted(merge):
|
|
241
|
+
if (value := merge[name]) is not None:
|
|
242
|
+
self.param(name, value)
|
|
243
|
+
else:
|
|
244
|
+
self.remove(name)
|
|
245
|
+
|
|
246
|
+
return self
|
|
247
|
+
|
|
248
|
+
def names(self) -> list[str]:
|
|
249
|
+
"""::
|
|
250
|
+
|
|
251
|
+
names = params.names()
|
|
252
|
+
|
|
253
|
+
Return a list with all parameter names. ::
|
|
254
|
+
|
|
255
|
+
# Names of all parameters
|
|
256
|
+
for name in params.names():
|
|
257
|
+
print(name)
|
|
258
|
+
"""
|
|
259
|
+
return sorted(self.to_dict())
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def pairs(self) -> list[tuple[str, str]]:
|
|
263
|
+
"""::
|
|
264
|
+
|
|
265
|
+
pairs = params.pairs
|
|
266
|
+
params.pairs = [('foo', 'b&ar'), ('baz', '23')]
|
|
267
|
+
|
|
268
|
+
Parsed parameter pairs. Note that this method will normalize the parameters. ::
|
|
269
|
+
|
|
270
|
+
# Remove all parameters
|
|
271
|
+
params.pairs = []
|
|
272
|
+
"""
|
|
273
|
+
# Parse string
|
|
274
|
+
if (string := self._string) is not None:
|
|
275
|
+
self._string = None
|
|
276
|
+
pairs: list[tuple[str, str]] = []
|
|
277
|
+
self._pairs = pairs
|
|
278
|
+
|
|
279
|
+
# Not in Mojolicious: bytes, which are a Perl byte string, the characters 0-255
|
|
280
|
+
if isinstance(string, (bytes, bytearray)):
|
|
281
|
+
string = string.decode('latin-1')
|
|
282
|
+
|
|
283
|
+
for pair in string.split('&'):
|
|
284
|
+
if not (m := re.match(r'^([^=]+)(?:=(.*))?$', pair)):
|
|
285
|
+
continue
|
|
286
|
+
name, value = m[1], m[2] or ''
|
|
287
|
+
|
|
288
|
+
# Replace "+" with whitespace, unescape and decode
|
|
289
|
+
name = self._decode(url_unescape(name.replace('+', ' ')))
|
|
290
|
+
value = self._decode(url_unescape(value.replace('+', ' ')))
|
|
291
|
+
|
|
292
|
+
pairs.append((name, value))
|
|
293
|
+
|
|
294
|
+
if self._pairs is None:
|
|
295
|
+
self._pairs = []
|
|
296
|
+
return self._pairs
|
|
297
|
+
|
|
298
|
+
@pairs.setter
|
|
299
|
+
def pairs(self, value: list[tuple[str, str]]) -> None:
|
|
300
|
+
self._pairs = value
|
|
301
|
+
self._string = None
|
|
302
|
+
|
|
303
|
+
@overload
|
|
304
|
+
def param(self, name: Anything, /) -> str | None: ...
|
|
305
|
+
|
|
306
|
+
@overload
|
|
307
|
+
def param(self, name: Anything, value: Anything, /, *values: Anything) -> Self: ...
|
|
308
|
+
|
|
309
|
+
def param(self, name: Anything, /, *values: Anything) -> str | None | Self:
|
|
310
|
+
"""::
|
|
311
|
+
|
|
312
|
+
value = params.param('foo')
|
|
313
|
+
params = params.param('foo', 'ba&r')
|
|
314
|
+
params = params.param('foo', 'ba&r', 'baz')
|
|
315
|
+
params = params.param('foo', ['ba;r', 'baz'])
|
|
316
|
+
|
|
317
|
+
Access parameter values. If there are multiple values sharing the same name,
|
|
318
|
+
and you want to access more than just the last one, you can use
|
|
319
|
+
:meth:`every_param`. Note that this method will normalize the parameters.
|
|
320
|
+
"""
|
|
321
|
+
if not values:
|
|
322
|
+
every = self.every_param(name)
|
|
323
|
+
return every[-1] if every else None
|
|
324
|
+
self.remove(name)
|
|
325
|
+
value = cast(list[Anything], values[0]) if len(values) == 1 and isinstance(values[0], list) else list(values)
|
|
326
|
+
return self.append(name, value)
|
|
327
|
+
|
|
328
|
+
def parse(self, *args: Anything, **kwargs: Anything) -> Self:
|
|
329
|
+
"""::
|
|
330
|
+
|
|
331
|
+
params = params.parse('foo=b%3Bar&baz=23')
|
|
332
|
+
params = params.parse(parse_qsl('foo=b%3Bar&baz=23'))
|
|
333
|
+
|
|
334
|
+
Parse parameters, given as characters or as bytes encoded with
|
|
335
|
+
:attr:`charset`. A list of pairs, as :func:`urllib.parse.parse_qsl` gives, or
|
|
336
|
+
a ``dict``, as :func:`urllib.parse.parse_qs` gives, is appended.
|
|
337
|
+
"""
|
|
338
|
+
# Pairs
|
|
339
|
+
# Not in Mojolicious: a list of pairs or a dict, as urllib.parse.parse_qsl
|
|
340
|
+
# and parse_qs give
|
|
341
|
+
if len(args) > 1 or kwargs or (args and isinstance(args[0], (tuple, list, dict, Pyjo_Parameters))):
|
|
342
|
+
return self.append(*args, **kwargs)
|
|
343
|
+
|
|
344
|
+
# String
|
|
345
|
+
# Not in Mojolicious: bytes, encoded with the charset
|
|
346
|
+
string = args[0] if args else None
|
|
347
|
+
self._string = (
|
|
348
|
+
'' if string is None else bytes(string) if isinstance(string, (bytes, bytearray)) else str(string)
|
|
349
|
+
)
|
|
350
|
+
self._pairs = None
|
|
351
|
+
return self
|
|
352
|
+
|
|
353
|
+
def remove(self, name: Anything) -> Self:
|
|
354
|
+
"""::
|
|
355
|
+
|
|
356
|
+
params = params.remove('foo')
|
|
357
|
+
|
|
358
|
+
Remove parameters. Note that this method will normalize the parameters. ::
|
|
359
|
+
|
|
360
|
+
# "bar=yada"
|
|
361
|
+
Pyjo.Parameters.new('foo=bar&foo=baz&bar=yada').remove('foo')
|
|
362
|
+
"""
|
|
363
|
+
name = str(name)
|
|
364
|
+
pairs = self.pairs
|
|
365
|
+
pairs[:] = [(n, v) for n, v in pairs if n != name]
|
|
366
|
+
return self
|
|
367
|
+
|
|
368
|
+
def to_dict(self) -> dict[str, str | list[str]]:
|
|
369
|
+
"""::
|
|
370
|
+
|
|
371
|
+
d = params.to_dict()
|
|
372
|
+
|
|
373
|
+
Turn parameters into a dict. Note that this method will normalize the
|
|
374
|
+
parameters. ::
|
|
375
|
+
|
|
376
|
+
# "baz"
|
|
377
|
+
Pyjo.Parameters.new('foo=bar&foo=baz').to_dict()['foo'][1]
|
|
378
|
+
"""
|
|
379
|
+
d: dict[str, str | list[str]] = {}
|
|
380
|
+
for name, value in self.pairs:
|
|
381
|
+
# List
|
|
382
|
+
if (old := d.get(name)) is not None:
|
|
383
|
+
if isinstance(old, list):
|
|
384
|
+
old.append(value)
|
|
385
|
+
else:
|
|
386
|
+
d[name] = [old, value]
|
|
387
|
+
|
|
388
|
+
# String
|
|
389
|
+
else:
|
|
390
|
+
d[name] = value
|
|
391
|
+
|
|
392
|
+
return d
|
|
393
|
+
|
|
394
|
+
def to_str(self) -> str:
|
|
395
|
+
"""::
|
|
396
|
+
|
|
397
|
+
string = params.to_str()
|
|
398
|
+
|
|
399
|
+
Turn parameters into a string. ::
|
|
400
|
+
|
|
401
|
+
# "foo=bar&baz=23"
|
|
402
|
+
Pyjo.Parameters.new().set(pairs=[('foo', 'bar'), ('baz', '23')]).to_str()
|
|
403
|
+
"""
|
|
404
|
+
# String (RFC 3986)
|
|
405
|
+
if (string := self._string) is not None:
|
|
406
|
+
return url_escape(self._encode(string), rb"^A-Za-z0-9\-._~%!$&'()*+,;=:@/?").decode('ascii')
|
|
407
|
+
|
|
408
|
+
# Build pairs (HTML Living Standard)
|
|
409
|
+
pairs: list[str] = []
|
|
410
|
+
for name, value in self.pairs:
|
|
411
|
+
# Escape and replace whitespace with "+"
|
|
412
|
+
name = url_escape(self._encode(name), rb'^*\-.0-9A-Z_a-z').decode('ascii').replace('%20', '+')
|
|
413
|
+
value = url_escape(self._encode(value), rb'^*\-.0-9A-Z_a-z').decode('ascii').replace('%20', '+')
|
|
414
|
+
pairs.append(f'{name}={value}')
|
|
415
|
+
|
|
416
|
+
return '&'.join(pairs)
|
|
417
|
+
|
|
418
|
+
# Not in Mojolicious: urllib of the standard library
|
|
419
|
+
def to_urllib(self) -> list[tuple[str, str]]:
|
|
420
|
+
"""::
|
|
421
|
+
|
|
422
|
+
pairs = params.to_urllib()
|
|
423
|
+
|
|
424
|
+
Turn parameters into a list of pairs, as :func:`urllib.parse.parse_qsl` gives,
|
|
425
|
+
for the standard library. ::
|
|
426
|
+
|
|
427
|
+
# "foo=bar&foo=baz"
|
|
428
|
+
urlencode(Pyjo.Parameters.new('foo=bar&foo=baz').to_urllib())
|
|
429
|
+
"""
|
|
430
|
+
return list(self.pairs)
|
|
431
|
+
|
|
432
|
+
def _decode(self, string: str) -> str:
|
|
433
|
+
# What does not decode stays characters 0-255, as a Perl byte string
|
|
434
|
+
decoded = decode(self.charset or 'latin-1', string)
|
|
435
|
+
return decoded if decoded is not None else string
|
|
436
|
+
|
|
437
|
+
def _encode(self, string: str | bytes) -> bytes:
|
|
438
|
+
# Without a charset, a character is a byte, as in a Perl byte string
|
|
439
|
+
return string if isinstance(string, bytes) else string.encode(self.charset or 'latin-1')
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
# A value as a string, and bytes as the characters 0-255, as Perl has a byte string, which a charset encodes as
|
|
443
|
+
# characters, as Mojo does
|
|
444
|
+
def _str(value: Anything) -> str:
|
|
445
|
+
return value.decode('latin-1') if isinstance(value, (bytes, bytearray)) else str(value)
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def _pairs(args: tuple[Anything, ...], kwargs: dict[str, Anything]) -> Iterator[tuple[str, Anything]]:
|
|
449
|
+
# Parameters as pairs: from another object, as tuples, as names followed by
|
|
450
|
+
# their values, and as keyword arguments
|
|
451
|
+
# Not in Mojolicious: tuples and keyword arguments, next to Mojo's names
|
|
452
|
+
# followed by their values
|
|
453
|
+
items = iter(args)
|
|
454
|
+
for item in items:
|
|
455
|
+
if isinstance(item, Pyjo_Parameters):
|
|
456
|
+
yield from item.pairs
|
|
457
|
+
elif isinstance(item, tuple):
|
|
458
|
+
name, value = cast(tuple[Anything, Anything], item)
|
|
459
|
+
yield str(name), value
|
|
460
|
+
# Not in Mojolicious: a list of pairs or a dict of the standard library
|
|
461
|
+
elif isinstance(item, list):
|
|
462
|
+
yield from _pairs(tuple(cast(list[Anything], item)), {})
|
|
463
|
+
elif isinstance(item, dict):
|
|
464
|
+
yield from ((str(n), v) for n, v in cast(dict[Anything, Anything], item).items())
|
|
465
|
+
else:
|
|
466
|
+
yield str(item), next(items, None)
|
|
467
|
+
yield from kwargs.items()
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
new = Pyjo_Parameters.new
|
|
471
|
+
object = Pyjo_Parameters
|
|
472
|
+
Parameters = Pyjo_Parameters
|