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/Collection.py
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Pyjo.Collection - Collection
|
|
3
|
+
============================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
from Pyjo.Collection import Collection
|
|
7
|
+
|
|
8
|
+
# Manipulate collection
|
|
9
|
+
collection = Collection(['just', 'works'])
|
|
10
|
+
collection.insert(0, 'it')
|
|
11
|
+
print(collection.join("\n"))
|
|
12
|
+
|
|
13
|
+
# Or import the module, as in Google Python Style Guide
|
|
14
|
+
|
|
15
|
+
import Pyjo.Collection
|
|
16
|
+
|
|
17
|
+
# Manipulate collection
|
|
18
|
+
collection = Pyjo.Collection.new('just', 'works')
|
|
19
|
+
collection.insert(0, 'it')
|
|
20
|
+
print(collection.join("\n"))
|
|
21
|
+
|
|
22
|
+
# Chain methods
|
|
23
|
+
collection.map(lambda e: e.capitalize()).shuffle().each(lambda word, num: print(f'{num}: {word}'))
|
|
24
|
+
|
|
25
|
+
# Use the alternative constructor
|
|
26
|
+
from Pyjo.Collection import c
|
|
27
|
+
c('a', 'b', 'c').join('/').url_escape().say()
|
|
28
|
+
|
|
29
|
+
:mod:`Pyjo.Collection` is a :class:`list` for collections. The class itself
|
|
30
|
+
takes an iterable, as :class:`list` does. ::
|
|
31
|
+
|
|
32
|
+
# Access list directly to manipulate collection
|
|
33
|
+
collection = Pyjo.Collection.new(*range(1, 26))
|
|
34
|
+
collection[23] += 100
|
|
35
|
+
for e in collection:
|
|
36
|
+
print(e)
|
|
37
|
+
|
|
38
|
+
# Make a collection of an iterable
|
|
39
|
+
collection = Pyjo.Collection.object(range(1, 26))
|
|
40
|
+
|
|
41
|
+
See also
|
|
42
|
+
--------
|
|
43
|
+
|
|
44
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
45
|
+
|
|
46
|
+
Ported from `Mojo::Collection <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojo/Collection.pm>`_
|
|
47
|
+
of Mojolicious 9.49.
|
|
48
|
+
|
|
49
|
+
Functions
|
|
50
|
+
---------
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
import Pyjo.Base
|
|
54
|
+
import Pyjo.String.Unicode
|
|
55
|
+
|
|
56
|
+
import builtins
|
|
57
|
+
import functools
|
|
58
|
+
import random
|
|
59
|
+
import re
|
|
60
|
+
|
|
61
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
62
|
+
from typing import Any, Self, cast, overload
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
type Anything = builtins.object
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Pyjo_Collection[T](list[T]):
|
|
69
|
+
"""
|
|
70
|
+
:mod:`Pyjo.Collection` inherits all methods from :class:`list` and
|
|
71
|
+
implements the following new ones.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def __repr__(self) -> str:
|
|
75
|
+
return f'{self.__module__}.new({", ".join(map(repr, self))})'
|
|
76
|
+
|
|
77
|
+
def __json__(self) -> list[T]:
|
|
78
|
+
"""::
|
|
79
|
+
|
|
80
|
+
array = collection.__json__()
|
|
81
|
+
|
|
82
|
+
Alias for :meth:`to_list`.
|
|
83
|
+
"""
|
|
84
|
+
return self.to_list()
|
|
85
|
+
|
|
86
|
+
def compact(self) -> Self:
|
|
87
|
+
"""::
|
|
88
|
+
|
|
89
|
+
new = collection.compact()
|
|
90
|
+
|
|
91
|
+
Create a new collection with all elements that are not ``None`` and not
|
|
92
|
+
an empty string. ::
|
|
93
|
+
|
|
94
|
+
# "0, 1, 2, 3"
|
|
95
|
+
c(0, 1, None, 2, '', 3).compact().join(', ')
|
|
96
|
+
"""
|
|
97
|
+
return type(self)(e for e in self if e is not None and (not isinstance(e, (str, bytes)) or len(e)))
|
|
98
|
+
|
|
99
|
+
@overload
|
|
100
|
+
def each(self) -> list[T]: ...
|
|
101
|
+
|
|
102
|
+
@overload
|
|
103
|
+
def each(self, cb: Callable[[T, int], Any]) -> Self: ...
|
|
104
|
+
|
|
105
|
+
def each(self, cb: Callable[[T, int], Any] | None = None) -> list[T] | Self:
|
|
106
|
+
"""::
|
|
107
|
+
|
|
108
|
+
elements = collection.each()
|
|
109
|
+
collection = collection.each(lambda e, num: ...)
|
|
110
|
+
|
|
111
|
+
Evaluate callback for each element in collection, or return all
|
|
112
|
+
elements as a list if none has been provided. The element will be the
|
|
113
|
+
first argument passed to the callback, and its number the second. ::
|
|
114
|
+
|
|
115
|
+
# Make a numbered list
|
|
116
|
+
collection.each(lambda e, num: print(f'{num}: {e}'))
|
|
117
|
+
"""
|
|
118
|
+
if cb is None:
|
|
119
|
+
return self.to_list()
|
|
120
|
+
for i, e in enumerate(self, 1):
|
|
121
|
+
cb(e, i)
|
|
122
|
+
return self
|
|
123
|
+
|
|
124
|
+
@overload
|
|
125
|
+
def first(self, cb: Callable[[T], object] | None = None, /) -> T | None: ...
|
|
126
|
+
|
|
127
|
+
@overload
|
|
128
|
+
def first(self, cb: Callable[..., Any] | str | re.Pattern[str], /, *args: Any, **kwargs: Any) -> T | None: ...
|
|
129
|
+
|
|
130
|
+
def first(
|
|
131
|
+
self, cb: Callable[..., Any] | str | re.Pattern[str] | None = None, /, *args: Any, **kwargs: Any
|
|
132
|
+
) -> T | None:
|
|
133
|
+
"""::
|
|
134
|
+
|
|
135
|
+
first = collection.first()
|
|
136
|
+
first = collection.first(re.compile(r'foo'))
|
|
137
|
+
first = collection.first(lambda e: ...)
|
|
138
|
+
first = collection.first('some_method')
|
|
139
|
+
first = collection.first('some_method', *args)
|
|
140
|
+
|
|
141
|
+
Evaluate regular expression/callback for, or call method on, each
|
|
142
|
+
element in collection and return the first one that matched the
|
|
143
|
+
regular expression, or for which the callback/method returned true.
|
|
144
|
+
The element will be the first argument passed to the callback. ::
|
|
145
|
+
|
|
146
|
+
# Longer version
|
|
147
|
+
first = collection.first(lambda e: e.some_method(*args))
|
|
148
|
+
|
|
149
|
+
# Find first value that contains the word "pyjo"
|
|
150
|
+
interesting = collection.first(re.compile(r'pyjo', re.I))
|
|
151
|
+
|
|
152
|
+
# Find first value that is greater than 5
|
|
153
|
+
greater = collection.first(lambda e: e > 5)
|
|
154
|
+
"""
|
|
155
|
+
if cb is None:
|
|
156
|
+
return self[0] if len(self) else None
|
|
157
|
+
if isinstance(cb, re.Pattern):
|
|
158
|
+
return next((e for e in self if cb.search(_str(e))), None)
|
|
159
|
+
return next((e for e in self if _call(e, cb, args, kwargs)), None)
|
|
160
|
+
|
|
161
|
+
def flatten(self) -> 'Pyjo_Collection[Any]':
|
|
162
|
+
"""::
|
|
163
|
+
|
|
164
|
+
new = collection.flatten()
|
|
165
|
+
|
|
166
|
+
Flatten nested collections/lists/tuples recursively and create a new
|
|
167
|
+
collection with all elements. ::
|
|
168
|
+
|
|
169
|
+
# "1, 2, 3, 4, 5, 6, 7"
|
|
170
|
+
c(1, [2, [3, 4], 5, [6]], 7).flatten().join(', ')
|
|
171
|
+
"""
|
|
172
|
+
return cast(Pyjo_Collection[Any], type(self)(_flatten(self)))
|
|
173
|
+
|
|
174
|
+
# Not in Mojolicious: the expression form of an index with a default, as
|
|
175
|
+
# dict.get() is
|
|
176
|
+
@overload
|
|
177
|
+
def get(self, index: int) -> T | None: ...
|
|
178
|
+
|
|
179
|
+
@overload
|
|
180
|
+
def get[D](self, index: int, default: D) -> T | D: ...
|
|
181
|
+
|
|
182
|
+
def get(self, index: int, default: Any = None) -> Any:
|
|
183
|
+
"""::
|
|
184
|
+
|
|
185
|
+
element = collection.get(index)
|
|
186
|
+
element = collection.get(index, default)
|
|
187
|
+
|
|
188
|
+
Return the element at the index, or the default, which is ``None``
|
|
189
|
+
unless given, if there is no such element. A negative index counts
|
|
190
|
+
from the end. ::
|
|
191
|
+
|
|
192
|
+
import sys
|
|
193
|
+
from Pyjo.Util import die
|
|
194
|
+
address = c(*sys.argv).get(1) or die('address missing')
|
|
195
|
+
port = int(c(*sys.argv).get(2, '80'))
|
|
196
|
+
"""
|
|
197
|
+
return self[index] if -len(self) <= index < len(self) else default
|
|
198
|
+
|
|
199
|
+
@overload
|
|
200
|
+
def grep(self, cb: Callable[[T], object], /) -> Self: ...
|
|
201
|
+
|
|
202
|
+
@overload
|
|
203
|
+
def grep(self, cb: Callable[..., Any] | str | re.Pattern[str], /, *args: Any, **kwargs: Any) -> Self: ...
|
|
204
|
+
|
|
205
|
+
def grep(self, cb: Callable[..., Any] | str | re.Pattern[str], /, *args: Any, **kwargs: Any) -> Self:
|
|
206
|
+
"""::
|
|
207
|
+
|
|
208
|
+
new = collection.grep(re.compile(r'foo'))
|
|
209
|
+
new = collection.grep(lambda e: ...)
|
|
210
|
+
new = collection.grep('some_method')
|
|
211
|
+
new = collection.grep('some_method', *args)
|
|
212
|
+
|
|
213
|
+
Evaluate regular expression/callback for, or call method on, each
|
|
214
|
+
element in collection and create a new collection with all elements
|
|
215
|
+
that matched the regular expression, or for which the callback/method
|
|
216
|
+
returned true. The element will be the first argument passed to the
|
|
217
|
+
callback. ::
|
|
218
|
+
|
|
219
|
+
# Longer version
|
|
220
|
+
new = collection.grep(lambda e: e.some_method(*args))
|
|
221
|
+
|
|
222
|
+
# Find all values that contain the word "pyjo"
|
|
223
|
+
interesting = collection.grep(re.compile(r'pyjo', re.I))
|
|
224
|
+
|
|
225
|
+
# Find all values that are greater than 5
|
|
226
|
+
greater = collection.grep(lambda e: e > 5)
|
|
227
|
+
"""
|
|
228
|
+
if isinstance(cb, re.Pattern):
|
|
229
|
+
return type(self)(e for e in self if cb.search(_str(e)))
|
|
230
|
+
return type(self)(e for e in self if _call(e, cb, args, kwargs))
|
|
231
|
+
|
|
232
|
+
def head(self, size: int) -> Self:
|
|
233
|
+
"""::
|
|
234
|
+
|
|
235
|
+
new = collection.head(4)
|
|
236
|
+
new = collection.head(-2)
|
|
237
|
+
|
|
238
|
+
Create a new collection with up to the specified number of elements
|
|
239
|
+
from the beginning of the collection. A negative number will count
|
|
240
|
+
from the end. ::
|
|
241
|
+
|
|
242
|
+
# "A B C"
|
|
243
|
+
c('A', 'B', 'C', 'D', 'E').head(3).join(' ')
|
|
244
|
+
|
|
245
|
+
# "A B"
|
|
246
|
+
c('A', 'B', 'C', 'D', 'E').head(-3).join(' ')
|
|
247
|
+
"""
|
|
248
|
+
return type(self)(self[:size])
|
|
249
|
+
|
|
250
|
+
def join(self, string: str | None = None) -> 'Pyjo.String.Unicode.object':
|
|
251
|
+
r"""::
|
|
252
|
+
|
|
253
|
+
string = collection.join()
|
|
254
|
+
string = collection.join("\n")
|
|
255
|
+
|
|
256
|
+
Turn collection into :mod:`Pyjo.String.Unicode`. ::
|
|
257
|
+
|
|
258
|
+
# Join all values with commas
|
|
259
|
+
collection.join(', ').say()
|
|
260
|
+
"""
|
|
261
|
+
return Pyjo.String.Unicode.new((string or '').join(map(_str, self)))
|
|
262
|
+
|
|
263
|
+
def last(self) -> T | None:
|
|
264
|
+
"""::
|
|
265
|
+
|
|
266
|
+
last = collection.last()
|
|
267
|
+
|
|
268
|
+
Return the last element in collection.
|
|
269
|
+
"""
|
|
270
|
+
return self[-1] if len(self) else None
|
|
271
|
+
|
|
272
|
+
@overload
|
|
273
|
+
def map[U](self, cb: Callable[[T], U], /) -> 'Pyjo_Collection[U]': ...
|
|
274
|
+
|
|
275
|
+
@overload
|
|
276
|
+
def map(self, cb: Callable[..., Any] | str, /, *args: Any, **kwargs: Any) -> 'Pyjo_Collection[Any]': ...
|
|
277
|
+
|
|
278
|
+
def map(self, cb: Callable[..., Any] | str, /, *args: Any, **kwargs: Any) -> 'Pyjo_Collection[Any]':
|
|
279
|
+
"""::
|
|
280
|
+
|
|
281
|
+
new = collection.map(lambda e: ...)
|
|
282
|
+
new = collection.map('some_method')
|
|
283
|
+
new = collection.map('some_method', *args)
|
|
284
|
+
|
|
285
|
+
Evaluate callback for, or call method on, each element in collection
|
|
286
|
+
and create a new collection from the results. The element will be the
|
|
287
|
+
first argument passed to the callback. ::
|
|
288
|
+
|
|
289
|
+
# Longer version
|
|
290
|
+
new = collection.map(lambda e: e.some_method(*args))
|
|
291
|
+
|
|
292
|
+
# Append the word "pyjo" to all values
|
|
293
|
+
pyjoified = collection.map(lambda e: e + 'pyjo')
|
|
294
|
+
"""
|
|
295
|
+
return cast(Pyjo_Collection[Any], type(self)(_call(e, cb, args, kwargs) for e in self))
|
|
296
|
+
|
|
297
|
+
@classmethod
|
|
298
|
+
def new(cls, *elements: T) -> Self:
|
|
299
|
+
"""::
|
|
300
|
+
|
|
301
|
+
collection = Pyjo.Collection.new(1, 2, 3)
|
|
302
|
+
|
|
303
|
+
Construct a new :mod:`Pyjo.Collection` object. The constructor of the
|
|
304
|
+
class takes an iterable, as the one of :class:`list`, so that a single
|
|
305
|
+
element that is iterable stays one element of :meth:`new`. ::
|
|
306
|
+
|
|
307
|
+
collection = Collection([1, 2, 3])
|
|
308
|
+
collection = Collection(n for n in range(3))
|
|
309
|
+
"""
|
|
310
|
+
return cls(elements)
|
|
311
|
+
|
|
312
|
+
def reduce(self, cb: Callable[[Any, T], Any], *initial: Any) -> Any:
|
|
313
|
+
"""::
|
|
314
|
+
|
|
315
|
+
result = collection.reduce(lambda a, b: ...)
|
|
316
|
+
result = collection.reduce(lambda a, b: ..., initial)
|
|
317
|
+
|
|
318
|
+
Reduce elements in collection with a callback and return its final
|
|
319
|
+
result, passing ``a`` and ``b`` each time the callback is executed. The
|
|
320
|
+
first time ``a`` will be an optional initial value or the first element
|
|
321
|
+
in the collection. And from then on ``a`` will be the return value of
|
|
322
|
+
the callback, while ``b`` will always be the next element in the
|
|
323
|
+
collection. ::
|
|
324
|
+
|
|
325
|
+
# Calculate the sum of all values
|
|
326
|
+
total = collection.reduce(lambda a, b: a + b)
|
|
327
|
+
|
|
328
|
+
# Count how often each value occurs in collection
|
|
329
|
+
counts = collection.reduce(lambda a, b: a | {b: a.get(b, 0) + 1}, {})
|
|
330
|
+
"""
|
|
331
|
+
elements = [*initial, *self]
|
|
332
|
+
return functools.reduce(cb, elements) if len(elements) else None
|
|
333
|
+
|
|
334
|
+
# Mojo's reverse creates a new collection, list.reverse() reverses in place
|
|
335
|
+
def reverse(self) -> Self: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
336
|
+
"""::
|
|
337
|
+
|
|
338
|
+
new = collection.reverse()
|
|
339
|
+
|
|
340
|
+
Create a new collection with all elements in reverse order.
|
|
341
|
+
"""
|
|
342
|
+
return type(self)(reversed(self))
|
|
343
|
+
|
|
344
|
+
def shuffle(self) -> Self:
|
|
345
|
+
"""::
|
|
346
|
+
|
|
347
|
+
new = collection.shuffle()
|
|
348
|
+
|
|
349
|
+
Create a new collection with all elements in random order.
|
|
350
|
+
"""
|
|
351
|
+
return type(self)(random.sample(self, len(self)))
|
|
352
|
+
|
|
353
|
+
@property
|
|
354
|
+
def size(self) -> int:
|
|
355
|
+
"""::
|
|
356
|
+
|
|
357
|
+
size = collection.size
|
|
358
|
+
|
|
359
|
+
Number of elements in collection.
|
|
360
|
+
"""
|
|
361
|
+
return len(self)
|
|
362
|
+
|
|
363
|
+
# Mojo's sort creates a new collection, list.sort() sorts in place
|
|
364
|
+
def sort( # pyright: ignore[reportIncompatibleMethodOverride]
|
|
365
|
+
self, *, key: Callable[[T], Any] | None = None, reverse: bool = False
|
|
366
|
+
) -> Self:
|
|
367
|
+
"""::
|
|
368
|
+
|
|
369
|
+
new = collection.sort()
|
|
370
|
+
new = collection.sort(key=lambda e: ...)
|
|
371
|
+
new = collection.sort(reverse=True)
|
|
372
|
+
|
|
373
|
+
Sort elements based on return value of a key function and create a new
|
|
374
|
+
collection from the results, as :func:`sorted` does. ::
|
|
375
|
+
|
|
376
|
+
# Sort values case-insensitive
|
|
377
|
+
case_insensitive = collection.sort(key=str.upper)
|
|
378
|
+
"""
|
|
379
|
+
# Unlike Mojolicious: Mojo takes a function that compares $a and $b, which
|
|
380
|
+
# Python 3 has no use for; the key and reverse arguments are sorted()'s
|
|
381
|
+
return type(self)(sorted(cast(list[Any], self), key=key, reverse=reverse))
|
|
382
|
+
|
|
383
|
+
def tail(self, size: int) -> Self:
|
|
384
|
+
"""::
|
|
385
|
+
|
|
386
|
+
new = collection.tail(4)
|
|
387
|
+
new = collection.tail(-2)
|
|
388
|
+
|
|
389
|
+
Create a new collection with up to the specified number of elements
|
|
390
|
+
from the end of the collection. A negative number will count from the
|
|
391
|
+
beginning. ::
|
|
392
|
+
|
|
393
|
+
# "C D E"
|
|
394
|
+
c('A', 'B', 'C', 'D', 'E').tail(3).join(' ')
|
|
395
|
+
|
|
396
|
+
# "D E"
|
|
397
|
+
c('A', 'B', 'C', 'D', 'E').tail(-3).join(' ')
|
|
398
|
+
"""
|
|
399
|
+
return type(self)(self[max(len(self) - size, 0) :] if size >= 0 else self[-size:])
|
|
400
|
+
|
|
401
|
+
def tap(self, cb: Callable[..., Any] | str, *args: Any, **kwargs: Any) -> Self:
|
|
402
|
+
"""::
|
|
403
|
+
|
|
404
|
+
collection = collection.tap(lambda c: ...)
|
|
405
|
+
|
|
406
|
+
Alias for :meth:`Pyjo.Base.tap`.
|
|
407
|
+
"""
|
|
408
|
+
Pyjo.Base.tap(self, cb, *args, **kwargs)
|
|
409
|
+
return self
|
|
410
|
+
|
|
411
|
+
# Not in Mojolicious: a conversion to a type of the standard library
|
|
412
|
+
def to_dict[K, V](self: 'Pyjo_Collection[tuple[K, V]]') -> dict[K, V]:
|
|
413
|
+
"""::
|
|
414
|
+
|
|
415
|
+
d = collection.to_dict()
|
|
416
|
+
|
|
417
|
+
Turn collection of pairs of key and value into :class:`dict`. ::
|
|
418
|
+
|
|
419
|
+
# {'a': 1, 'b': 2, 'c': 3}
|
|
420
|
+
c(('a', 1), ('b', 2), ('c', 3)).to_dict()
|
|
421
|
+
"""
|
|
422
|
+
return dict(self)
|
|
423
|
+
|
|
424
|
+
# Not in Mojolicious: a conversion to a type of the standard library
|
|
425
|
+
def to_iter(self) -> Iterator[T]:
|
|
426
|
+
"""::
|
|
427
|
+
|
|
428
|
+
i = collection.to_iter()
|
|
429
|
+
|
|
430
|
+
Turn collection into an iterator. ::
|
|
431
|
+
|
|
432
|
+
for e in c(1, 2, 3).to_iter():
|
|
433
|
+
print(e)
|
|
434
|
+
"""
|
|
435
|
+
return iter(self)
|
|
436
|
+
|
|
437
|
+
def to_list(self) -> list[T]:
|
|
438
|
+
"""::
|
|
439
|
+
|
|
440
|
+
array = collection.to_list()
|
|
441
|
+
|
|
442
|
+
Turn collection into :class:`list`.
|
|
443
|
+
"""
|
|
444
|
+
return list(self)
|
|
445
|
+
|
|
446
|
+
# Not in Mojolicious: a conversion to a type of the standard library
|
|
447
|
+
def to_set(self) -> set[T]:
|
|
448
|
+
"""::
|
|
449
|
+
|
|
450
|
+
s = collection.to_set()
|
|
451
|
+
|
|
452
|
+
Turn collection into :class:`set`. ::
|
|
453
|
+
|
|
454
|
+
# {1, 2, 3}
|
|
455
|
+
c(1, 2, 3, 2).to_set()
|
|
456
|
+
"""
|
|
457
|
+
return set(self)
|
|
458
|
+
|
|
459
|
+
# Not in Mojolicious: a conversion to a type of the standard library
|
|
460
|
+
def to_tuple(self) -> tuple[T, ...]:
|
|
461
|
+
"""::
|
|
462
|
+
|
|
463
|
+
t = collection.to_tuple()
|
|
464
|
+
|
|
465
|
+
Turn collection into :class:`tuple`. ::
|
|
466
|
+
|
|
467
|
+
# (1, 2, 3)
|
|
468
|
+
c(1, 2, 3).to_tuple()
|
|
469
|
+
"""
|
|
470
|
+
return tuple(self)
|
|
471
|
+
|
|
472
|
+
def uniq(self, cb: Callable[..., Any] | str | None = None, *args: Any, **kwargs: Any) -> Self:
|
|
473
|
+
"""::
|
|
474
|
+
|
|
475
|
+
new = collection.uniq()
|
|
476
|
+
new = collection.uniq(lambda e: ...)
|
|
477
|
+
new = collection.uniq('some_method')
|
|
478
|
+
new = collection.uniq('some_method', *args)
|
|
479
|
+
|
|
480
|
+
Create a new collection without duplicate elements, using the string
|
|
481
|
+
representation of either the elements or the return value of the
|
|
482
|
+
callback/method to decide uniqueness. Note that ``None`` and empty
|
|
483
|
+
string are treated the same. ::
|
|
484
|
+
|
|
485
|
+
# Longer version
|
|
486
|
+
new = collection.uniq(lambda e: e.some_method(*args))
|
|
487
|
+
|
|
488
|
+
# "foo bar baz"
|
|
489
|
+
c('foo', 'bar', 'bar', 'baz').uniq().join(' ')
|
|
490
|
+
|
|
491
|
+
# [[1, 2], [2, 1]]
|
|
492
|
+
c([1, 2], [2, 1], [3, 2]).uniq(lambda e: e[1]).to_list()
|
|
493
|
+
"""
|
|
494
|
+
seen: set[str] = set()
|
|
495
|
+
new = type(self)()
|
|
496
|
+
for e in self:
|
|
497
|
+
value = e if cb is None else _call(e, cb, args, kwargs)
|
|
498
|
+
if (key := '' if value is None else _str(value)) not in seen:
|
|
499
|
+
seen.add(key)
|
|
500
|
+
new.append(e)
|
|
501
|
+
return new
|
|
502
|
+
|
|
503
|
+
# Left out from Mojolicious: with_roles, as Pyjoyment has no roles
|
|
504
|
+
|
|
505
|
+
# Not in Mojolicious: the method form of zip(), for a chain
|
|
506
|
+
@overload
|
|
507
|
+
def zip[U](self, iterable: Iterable[U], /, *, strict: bool = False) -> 'Pyjo_Collection[tuple[T, U]]': ...
|
|
508
|
+
|
|
509
|
+
@overload
|
|
510
|
+
def zip(self, *iterables: Iterable[Any], strict: bool = False) -> 'Pyjo_Collection[tuple[Any, ...]]': ...
|
|
511
|
+
|
|
512
|
+
def zip(self, *iterables: Iterable[Any], strict: bool = False) -> 'Pyjo_Collection[tuple[Any, ...]]':
|
|
513
|
+
"""::
|
|
514
|
+
|
|
515
|
+
new = collection.zip(iterable)
|
|
516
|
+
new = collection.zip(iterable, strict=True)
|
|
517
|
+
|
|
518
|
+
Create a new collection of tuples of the elements of the collection and
|
|
519
|
+
of the iterables, as :func:`zip` does. ::
|
|
520
|
+
|
|
521
|
+
# [('a', 1), ('b', 2), ('c', 3)]
|
|
522
|
+
c('a', 'b', 'c').zip([1, 2, 3]).to_list()
|
|
523
|
+
|
|
524
|
+
# {'a': 1, 'b': 2, 'c': 3}
|
|
525
|
+
c('a', 'b', 'c').zip([1, 2, 3]).to_dict()
|
|
526
|
+
"""
|
|
527
|
+
return cast(
|
|
528
|
+
Pyjo_Collection[tuple[Any, ...]], type(self)(cast(Iterable[Any], zip(self, *iterables, strict=strict)))
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def c[T](*elements: T) -> Pyjo_Collection[T]:
|
|
533
|
+
"""::
|
|
534
|
+
|
|
535
|
+
collection = c(1, 2, 3)
|
|
536
|
+
|
|
537
|
+
Construct a new :mod:`Pyjo.Collection` object.
|
|
538
|
+
"""
|
|
539
|
+
return Pyjo_Collection(elements)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
# A method of the element, or Mojo's attribute, which is a property
|
|
543
|
+
def _call(element: Any, cb: Callable[..., Any] | str, args: tuple[Any, ...], kwargs: dict[str, Any]) -> Any:
|
|
544
|
+
if callable(cb):
|
|
545
|
+
return cb(element, *args, **kwargs)
|
|
546
|
+
value = getattr(element, cb)
|
|
547
|
+
if callable(value):
|
|
548
|
+
return value(*args, **kwargs)
|
|
549
|
+
if len(args):
|
|
550
|
+
setattr(element, cb, args[0])
|
|
551
|
+
return element
|
|
552
|
+
return value
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def _flatten(elements: Iterable[Any]) -> Iterable[Any]:
|
|
556
|
+
for e in elements:
|
|
557
|
+
if isinstance(e, (list, tuple)):
|
|
558
|
+
yield from _flatten(cast(Iterable[Any], e))
|
|
559
|
+
else:
|
|
560
|
+
yield e
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def _str(element: Anything) -> str:
|
|
564
|
+
return Pyjo.String.Unicode.new(element).to_str()
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
# Any: the type of the elements is not known before they are given
|
|
568
|
+
new = Pyjo_Collection[Any].new
|
|
569
|
+
object = Pyjo_Collection
|
|
570
|
+
Collection = Pyjo_Collection
|