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
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Pyjo.Transaction - Transaction base class
|
|
3
|
+
=========================================
|
|
4
|
+
::
|
|
5
|
+
|
|
6
|
+
from Pyjo.Transaction import Transaction
|
|
7
|
+
|
|
8
|
+
class MyTransaction(Transaction):
|
|
9
|
+
def client_read(self, chunk): ...
|
|
10
|
+
def client_write(self): ...
|
|
11
|
+
def server_read(self, chunk): ...
|
|
12
|
+
def server_write(self): ...
|
|
13
|
+
|
|
14
|
+
# Or import the module, as in Google Python Style Guide
|
|
15
|
+
|
|
16
|
+
import Pyjo.Transaction
|
|
17
|
+
|
|
18
|
+
class MyTransaction(Pyjo.Transaction.object):
|
|
19
|
+
def client_read(self, chunk): ...
|
|
20
|
+
def client_write(self): ...
|
|
21
|
+
def server_read(self, chunk): ...
|
|
22
|
+
def server_write(self): ...
|
|
23
|
+
|
|
24
|
+
:mod:`Pyjo.Transaction` is an abstract base class for transactions, like
|
|
25
|
+
:mod:`Pyjo.Transaction.HTTP` and :mod:`Pyjo.Transaction.WebSocket`.
|
|
26
|
+
|
|
27
|
+
Events
|
|
28
|
+
------
|
|
29
|
+
|
|
30
|
+
:mod:`Pyjo.Transaction` inherits all events from :mod:`Pyjo.EventEmitter` and
|
|
31
|
+
can emit the following new ones.
|
|
32
|
+
|
|
33
|
+
connection
|
|
34
|
+
~~~~~~~~~~
|
|
35
|
+
::
|
|
36
|
+
|
|
37
|
+
tx.on('connection', lambda tx, connection: ...)
|
|
38
|
+
|
|
39
|
+
Emitted when a connection has been assigned to transaction.
|
|
40
|
+
|
|
41
|
+
finish
|
|
42
|
+
~~~~~~
|
|
43
|
+
::
|
|
44
|
+
|
|
45
|
+
tx.on('finish', lambda tx: ...)
|
|
46
|
+
|
|
47
|
+
Emitted when transaction is finished.
|
|
48
|
+
|
|
49
|
+
See also
|
|
50
|
+
--------
|
|
51
|
+
|
|
52
|
+
:mod:`Pyjoyment`, https://mojolicious.org.
|
|
53
|
+
|
|
54
|
+
Ported from `Mojo::Transaction <https://github.com/mojolicious/mojo/blob/v9.49/lib/Mojo/Transaction.pm>`_
|
|
55
|
+
of Mojolicious 9.49.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
import Pyjo.EventEmitter
|
|
59
|
+
import Pyjo.Exception
|
|
60
|
+
import Pyjo.Message
|
|
61
|
+
import Pyjo.Message.Request
|
|
62
|
+
import Pyjo.Message.Response
|
|
63
|
+
|
|
64
|
+
from Pyjo.String.Unicode import split
|
|
65
|
+
from Pyjo.Util import network_contains
|
|
66
|
+
|
|
67
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Pyjo_Transaction(Pyjo.EventEmitter.object):
|
|
71
|
+
"""
|
|
72
|
+
:mod:`Pyjo.Transaction` inherits all methods from :mod:`Pyjo.EventEmitter`
|
|
73
|
+
and implements the following new ones.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(
|
|
77
|
+
self,
|
|
78
|
+
*,
|
|
79
|
+
kept_alive: bool | None = None,
|
|
80
|
+
local_address: str | None = None,
|
|
81
|
+
local_port: int | None = None,
|
|
82
|
+
original_remote_address: str | None = None,
|
|
83
|
+
remote_port: int | None = None,
|
|
84
|
+
req: Pyjo.Message.Request.object | None = None,
|
|
85
|
+
res: Pyjo.Message.Response.object | None = None,
|
|
86
|
+
) -> None:
|
|
87
|
+
"""::
|
|
88
|
+
|
|
89
|
+
tx = Pyjo.Transaction.HTTP.new()
|
|
90
|
+
tx = Pyjo.Transaction.HTTP.new(req=Pyjo.Message.Request.new())
|
|
91
|
+
|
|
92
|
+
Construct a new transaction object.
|
|
93
|
+
"""
|
|
94
|
+
super().__init__()
|
|
95
|
+
|
|
96
|
+
self.original_remote_address = original_remote_address
|
|
97
|
+
"""::
|
|
98
|
+
|
|
99
|
+
address = tx.original_remote_address
|
|
100
|
+
tx.original_remote_address = '127.0.0.1'
|
|
101
|
+
|
|
102
|
+
Remote interface address.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
self._kept_alive = kept_alive
|
|
106
|
+
self._local_address = local_address
|
|
107
|
+
self._local_port = local_port
|
|
108
|
+
self._remote_port = remote_port
|
|
109
|
+
self._req = req
|
|
110
|
+
self._res = res
|
|
111
|
+
|
|
112
|
+
# The state of the transaction, as the keys of Mojo's hash
|
|
113
|
+
self._completed = False
|
|
114
|
+
self._connection: str | None = None
|
|
115
|
+
|
|
116
|
+
if not TYPE_CHECKING:
|
|
117
|
+
# Not in Mojolicious: the transaction of a blocking request used as a decorator, as @ua.get(url) over a
|
|
118
|
+
# callback; out of the sight of type checkers, which would take a transaction for a callable
|
|
119
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
|
120
|
+
raise TypeError(
|
|
121
|
+
f"'{type(self).__name__}' object is not callable: a request without a callback is blocking and returns"
|
|
122
|
+
' its transaction, a non-blocking one takes its callback as the last argument or cb=..., or is a promise'
|
|
123
|
+
' of get_p(...)'
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def kept_alive(self) -> bool | None:
|
|
128
|
+
"""::
|
|
129
|
+
|
|
130
|
+
boolean = tx.kept_alive
|
|
131
|
+
tx.kept_alive = boolean
|
|
132
|
+
|
|
133
|
+
Connection has been kept alive.
|
|
134
|
+
"""
|
|
135
|
+
return self._kept_alive
|
|
136
|
+
|
|
137
|
+
@kept_alive.setter
|
|
138
|
+
def kept_alive(self, value: bool | None) -> None:
|
|
139
|
+
self._kept_alive = value
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def local_address(self) -> str | None:
|
|
143
|
+
"""::
|
|
144
|
+
|
|
145
|
+
address = tx.local_address
|
|
146
|
+
tx.local_address = '127.0.0.1'
|
|
147
|
+
|
|
148
|
+
Local interface address.
|
|
149
|
+
"""
|
|
150
|
+
return self._local_address
|
|
151
|
+
|
|
152
|
+
@local_address.setter
|
|
153
|
+
def local_address(self, value: str | None) -> None:
|
|
154
|
+
self._local_address = value
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def local_port(self) -> int | None:
|
|
158
|
+
"""::
|
|
159
|
+
|
|
160
|
+
port = tx.local_port
|
|
161
|
+
tx.local_port = 8080
|
|
162
|
+
|
|
163
|
+
Local interface port.
|
|
164
|
+
"""
|
|
165
|
+
return self._local_port
|
|
166
|
+
|
|
167
|
+
@local_port.setter
|
|
168
|
+
def local_port(self, value: int | None) -> None:
|
|
169
|
+
self._local_port = value
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def remote_port(self) -> int | None:
|
|
173
|
+
"""::
|
|
174
|
+
|
|
175
|
+
port = tx.remote_port
|
|
176
|
+
tx.remote_port = 8081
|
|
177
|
+
|
|
178
|
+
Remote interface port.
|
|
179
|
+
"""
|
|
180
|
+
return self._remote_port
|
|
181
|
+
|
|
182
|
+
@remote_port.setter
|
|
183
|
+
def remote_port(self, value: int | None) -> None:
|
|
184
|
+
self._remote_port = value
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def req(self) -> Pyjo.Message.Request.object:
|
|
188
|
+
"""::
|
|
189
|
+
|
|
190
|
+
req = tx.req
|
|
191
|
+
tx.req = Pyjo.Message.Request.new()
|
|
192
|
+
|
|
193
|
+
HTTP request, defaults to a :mod:`Pyjo.Message.Request` object. ::
|
|
194
|
+
|
|
195
|
+
# Access request information
|
|
196
|
+
method = tx.req.method
|
|
197
|
+
url = tx.req.url.to_abs()
|
|
198
|
+
info = tx.req.url.to_abs().userinfo
|
|
199
|
+
host = tx.req.url.to_abs().host
|
|
200
|
+
agent = tx.req.headers.user_agent
|
|
201
|
+
custom = tx.req.headers.header('Custom-Header')
|
|
202
|
+
data = tx.req.body
|
|
203
|
+
string = tx.req.text
|
|
204
|
+
params = tx.req.params.to_dict()
|
|
205
|
+
all = tx.req.uploads()
|
|
206
|
+
value = tx.req.json()
|
|
207
|
+
foo = tx.req.json('/23/foo')
|
|
208
|
+
dom = tx.req.dom()
|
|
209
|
+
bar = tx.req.dom('div.bar').first().text
|
|
210
|
+
"""
|
|
211
|
+
if self._req is None:
|
|
212
|
+
self._req = Pyjo.Message.Request.new()
|
|
213
|
+
return self._req
|
|
214
|
+
|
|
215
|
+
@req.setter
|
|
216
|
+
def req(self, value: Pyjo.Message.Request.object) -> None:
|
|
217
|
+
self._req = value
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def res(self) -> Pyjo.Message.Response.object:
|
|
221
|
+
"""::
|
|
222
|
+
|
|
223
|
+
res = tx.res
|
|
224
|
+
tx.res = Pyjo.Message.Response.new()
|
|
225
|
+
|
|
226
|
+
HTTP response, defaults to a :mod:`Pyjo.Message.Response` object. ::
|
|
227
|
+
|
|
228
|
+
# Access response information
|
|
229
|
+
code = tx.res.code
|
|
230
|
+
message = tx.res.message
|
|
231
|
+
server = tx.res.headers.server
|
|
232
|
+
custom = tx.res.headers.header('Custom-Header')
|
|
233
|
+
data = tx.res.body
|
|
234
|
+
string = tx.res.text
|
|
235
|
+
value = tx.res.json()
|
|
236
|
+
foo = tx.res.json('/23/foo')
|
|
237
|
+
dom = tx.res.dom()
|
|
238
|
+
bar = tx.res.dom('div.bar').first().text
|
|
239
|
+
"""
|
|
240
|
+
if self._res is None:
|
|
241
|
+
self._res = Pyjo.Message.Response.new()
|
|
242
|
+
return self._res
|
|
243
|
+
|
|
244
|
+
@res.setter
|
|
245
|
+
def res(self, value: Pyjo.Message.Response.object) -> None:
|
|
246
|
+
self._res = value
|
|
247
|
+
|
|
248
|
+
def client_read(self, chunk: bytes) -> object:
|
|
249
|
+
"""::
|
|
250
|
+
|
|
251
|
+
tx.client_read(data)
|
|
252
|
+
|
|
253
|
+
Read data client-side, used to implement user agents such as
|
|
254
|
+
:mod:`Pyjo.UserAgent`. Meant to be overloaded in a subclass.
|
|
255
|
+
"""
|
|
256
|
+
raise NotImplementedError('Method "client_read" not implemented by subclass')
|
|
257
|
+
|
|
258
|
+
def client_write(self) -> bytes:
|
|
259
|
+
"""::
|
|
260
|
+
|
|
261
|
+
data = tx.client_write()
|
|
262
|
+
|
|
263
|
+
Write data client-side, used to implement user agents such as
|
|
264
|
+
:mod:`Pyjo.UserAgent`. Meant to be overloaded in a subclass.
|
|
265
|
+
"""
|
|
266
|
+
raise NotImplementedError('Method "client_write" not implemented by subclass')
|
|
267
|
+
|
|
268
|
+
def closed(self) -> Self:
|
|
269
|
+
"""::
|
|
270
|
+
|
|
271
|
+
tx = tx.closed()
|
|
272
|
+
|
|
273
|
+
Same as :meth:`completed`, but also indicates that all transaction data
|
|
274
|
+
has been sent.
|
|
275
|
+
"""
|
|
276
|
+
return self.completed().emit('finish')
|
|
277
|
+
|
|
278
|
+
def completed(self) -> Self:
|
|
279
|
+
"""::
|
|
280
|
+
|
|
281
|
+
tx = tx.completed()
|
|
282
|
+
|
|
283
|
+
Low-level method to finalize transaction.
|
|
284
|
+
"""
|
|
285
|
+
self._completed = True
|
|
286
|
+
return self
|
|
287
|
+
|
|
288
|
+
@property
|
|
289
|
+
def connection(self) -> str | None:
|
|
290
|
+
"""::
|
|
291
|
+
|
|
292
|
+
id = tx.connection
|
|
293
|
+
tx.connection = id
|
|
294
|
+
|
|
295
|
+
Connection identifier, setting it emits the ``connection`` event.
|
|
296
|
+
"""
|
|
297
|
+
return self._connection
|
|
298
|
+
|
|
299
|
+
@connection.setter
|
|
300
|
+
def connection(self, value: str | None) -> None:
|
|
301
|
+
self._connection = value
|
|
302
|
+
self.emit('connection', value)
|
|
303
|
+
|
|
304
|
+
@property
|
|
305
|
+
def error(self) -> Pyjo.Message.Error | None:
|
|
306
|
+
"""::
|
|
307
|
+
|
|
308
|
+
err = tx.error
|
|
309
|
+
|
|
310
|
+
Get request or response error and return ``None`` if there is no
|
|
311
|
+
error. ::
|
|
312
|
+
|
|
313
|
+
# Longer version
|
|
314
|
+
err = tx.req.error or tx.res.error
|
|
315
|
+
|
|
316
|
+
# Check for 4xx/5xx response and connection errors
|
|
317
|
+
if err := tx.error:
|
|
318
|
+
if 'code' in err:
|
|
319
|
+
raise Exception(f'{err["code"]} response: {err["message"]}')
|
|
320
|
+
raise Exception(f'Connection error: {err["message"]}')
|
|
321
|
+
"""
|
|
322
|
+
return self.req.error or self.res.error
|
|
323
|
+
|
|
324
|
+
@property
|
|
325
|
+
def is_finished(self) -> bool:
|
|
326
|
+
"""::
|
|
327
|
+
|
|
328
|
+
boolean = tx.is_finished
|
|
329
|
+
|
|
330
|
+
Check if transaction is finished.
|
|
331
|
+
"""
|
|
332
|
+
return self._completed
|
|
333
|
+
|
|
334
|
+
@property
|
|
335
|
+
def is_websocket(self) -> bool:
|
|
336
|
+
"""::
|
|
337
|
+
|
|
338
|
+
boolean = tx.is_websocket
|
|
339
|
+
|
|
340
|
+
False, this is not a :mod:`Pyjo.Transaction.WebSocket` object.
|
|
341
|
+
"""
|
|
342
|
+
return False
|
|
343
|
+
|
|
344
|
+
@property
|
|
345
|
+
def remote_address(self) -> str | None:
|
|
346
|
+
"""::
|
|
347
|
+
|
|
348
|
+
address = tx.remote_address
|
|
349
|
+
tx.remote_address = '127.0.0.1'
|
|
350
|
+
|
|
351
|
+
Same as :attr:`original_remote_address` unless :attr:`req` has been
|
|
352
|
+
performed via a
|
|
353
|
+
:attr:`Pyjo.Message.Request.Pyjo_Message_Request.reverse_proxy`. If so
|
|
354
|
+
then the last value of ``X-Forwarded-For`` header is returned.
|
|
355
|
+
Additionally if
|
|
356
|
+
:attr:`Pyjo.Message.Request.Pyjo_Message_Request.trusted_proxies` are
|
|
357
|
+
also provided then the original address must be trusted and any
|
|
358
|
+
``X-Forwarded-For`` entries that are trusted are ignored, returning
|
|
359
|
+
the last untrusted address or the first address if all are trusted.
|
|
360
|
+
"""
|
|
361
|
+
if not self.req.reverse_proxy:
|
|
362
|
+
return self.original_remote_address
|
|
363
|
+
|
|
364
|
+
# Reverse proxy
|
|
365
|
+
forwarded = split(r'\s*,\s*', self.req.headers.header('X-Forwarded-For') or '')
|
|
366
|
+
addrs: list[str | None] = [a for a in forwarded if a is not None]
|
|
367
|
+
trusted = self.req.trusted_proxies
|
|
368
|
+
if not len(trusted):
|
|
369
|
+
return addrs[-1] if addrs else self.original_remote_address
|
|
370
|
+
|
|
371
|
+
addrs.append(self.original_remote_address)
|
|
372
|
+
for addr in reversed(addrs):
|
|
373
|
+
if not any(network_contains(t, addr or '') for t in trusted):
|
|
374
|
+
return addr
|
|
375
|
+
return addrs[0]
|
|
376
|
+
|
|
377
|
+
@remote_address.setter
|
|
378
|
+
def remote_address(self, value: str | None) -> None:
|
|
379
|
+
self.original_remote_address = value
|
|
380
|
+
|
|
381
|
+
@property
|
|
382
|
+
def result(self) -> Pyjo.Message.Response.object:
|
|
383
|
+
"""::
|
|
384
|
+
|
|
385
|
+
res = tx.result
|
|
386
|
+
|
|
387
|
+
Returns the :mod:`Pyjo.Message.Response` object from :attr:`res` or
|
|
388
|
+
raises an exception if a connection error has occurred. ::
|
|
389
|
+
|
|
390
|
+
# Fine grained response handling (raises on connection errors)
|
|
391
|
+
res = tx.result
|
|
392
|
+
if res.is_success:
|
|
393
|
+
print(res.body)
|
|
394
|
+
elif res.is_error:
|
|
395
|
+
print(res.message)
|
|
396
|
+
elif res.code == 301:
|
|
397
|
+
print(res.headers.location)
|
|
398
|
+
else:
|
|
399
|
+
print('Whatever...')
|
|
400
|
+
"""
|
|
401
|
+
err = self.error
|
|
402
|
+
if not err or err.get('code'):
|
|
403
|
+
return self.res
|
|
404
|
+
raise Pyjo.Exception.new(err['message'])
|
|
405
|
+
|
|
406
|
+
def server_read(self, chunk: bytes) -> object:
|
|
407
|
+
"""::
|
|
408
|
+
|
|
409
|
+
tx.server_read(data)
|
|
410
|
+
|
|
411
|
+
Read data server-side, used to implement web servers such as
|
|
412
|
+
:mod:`Pyjo.Server.Daemon`. Meant to be overloaded in a subclass.
|
|
413
|
+
"""
|
|
414
|
+
raise NotImplementedError('Method "server_read" not implemented by subclass')
|
|
415
|
+
|
|
416
|
+
def server_write(self) -> bytes:
|
|
417
|
+
"""::
|
|
418
|
+
|
|
419
|
+
data = tx.server_write()
|
|
420
|
+
|
|
421
|
+
Write data server-side, used to implement web servers such as
|
|
422
|
+
:mod:`Pyjo.Server.Daemon`. Meant to be overloaded in a subclass.
|
|
423
|
+
"""
|
|
424
|
+
raise NotImplementedError('Method "server_write" not implemented by subclass')
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
new = Pyjo_Transaction.new
|
|
428
|
+
object = Pyjo_Transaction
|
|
429
|
+
Transaction = Pyjo_Transaction
|