Spaces:
Running
Running
Upload 656 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/INSTALLER +1 -0
- MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/LICENSE.txt +28 -0
- MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/METADATA +99 -0
- MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/RECORD +125 -0
- MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/WHEEL +4 -0
- MLPY/Lib/site-packages/werkzeug/__init__.py +25 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/__init__.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/_internal.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/_reloader.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/exceptions.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/formparser.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/http.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/local.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/security.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/serving.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/test.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/testapp.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/urls.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/user_agent.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/utils.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/__pycache__/wsgi.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/_internal.py +211 -0
- MLPY/Lib/site-packages/werkzeug/_reloader.py +460 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__init__.py +34 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/range.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/accept.py +326 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/accept.pyi +54 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/auth.py +316 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/cache_control.py +175 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/cache_control.pyi +115 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/csp.py +94 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/csp.pyi +169 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/etag.py +95 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/etag.pyi +30 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/file_storage.py +196 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/file_storage.pyi +49 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/headers.py +515 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/headers.pyi +109 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/mixins.py +242 -0
- MLPY/Lib/site-packages/werkzeug/datastructures/mixins.pyi +97 -0
MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/INSTALLER
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
pip
|
MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/LICENSE.txt
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Copyright 2007 Pallets
|
2 |
+
|
3 |
+
Redistribution and use in source and binary forms, with or without
|
4 |
+
modification, are permitted provided that the following conditions are
|
5 |
+
met:
|
6 |
+
|
7 |
+
1. Redistributions of source code must retain the above copyright
|
8 |
+
notice, this list of conditions and the following disclaimer.
|
9 |
+
|
10 |
+
2. Redistributions in binary form must reproduce the above copyright
|
11 |
+
notice, this list of conditions and the following disclaimer in the
|
12 |
+
documentation and/or other materials provided with the distribution.
|
13 |
+
|
14 |
+
3. Neither the name of the copyright holder nor the names of its
|
15 |
+
contributors may be used to endorse or promote products derived from
|
16 |
+
this software without specific prior written permission.
|
17 |
+
|
18 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
21 |
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22 |
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
24 |
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
25 |
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26 |
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
27 |
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
28 |
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/METADATA
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Metadata-Version: 2.1
|
2 |
+
Name: Werkzeug
|
3 |
+
Version: 3.0.3
|
4 |
+
Summary: The comprehensive WSGI web application library.
|
5 |
+
Maintainer-email: Pallets <[email protected]>
|
6 |
+
Requires-Python: >=3.8
|
7 |
+
Description-Content-Type: text/markdown
|
8 |
+
Classifier: Development Status :: 5 - Production/Stable
|
9 |
+
Classifier: Environment :: Web Environment
|
10 |
+
Classifier: Intended Audience :: Developers
|
11 |
+
Classifier: License :: OSI Approved :: BSD License
|
12 |
+
Classifier: Operating System :: OS Independent
|
13 |
+
Classifier: Programming Language :: Python
|
14 |
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
15 |
+
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
|
16 |
+
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
|
17 |
+
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
|
18 |
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
19 |
+
Classifier: Typing :: Typed
|
20 |
+
Requires-Dist: MarkupSafe>=2.1.1
|
21 |
+
Requires-Dist: watchdog>=2.3 ; extra == "watchdog"
|
22 |
+
Project-URL: Changes, https://werkzeug.palletsprojects.com/changes/
|
23 |
+
Project-URL: Chat, https://discord.gg/pallets
|
24 |
+
Project-URL: Documentation, https://werkzeug.palletsprojects.com/
|
25 |
+
Project-URL: Donate, https://palletsprojects.com/donate
|
26 |
+
Project-URL: Issue Tracker, https://github.com/pallets/werkzeug/issues/
|
27 |
+
Project-URL: Source Code, https://github.com/pallets/werkzeug/
|
28 |
+
Provides-Extra: watchdog
|
29 |
+
|
30 |
+
# Werkzeug
|
31 |
+
|
32 |
+
*werkzeug* German noun: "tool". Etymology: *werk* ("work"), *zeug* ("stuff")
|
33 |
+
|
34 |
+
Werkzeug is a comprehensive [WSGI][] web application library. It began as
|
35 |
+
a simple collection of various utilities for WSGI applications and has
|
36 |
+
become one of the most advanced WSGI utility libraries.
|
37 |
+
|
38 |
+
It includes:
|
39 |
+
|
40 |
+
- An interactive debugger that allows inspecting stack traces and
|
41 |
+
source code in the browser with an interactive interpreter for any
|
42 |
+
frame in the stack.
|
43 |
+
- A full-featured request object with objects to interact with
|
44 |
+
headers, query args, form data, files, and cookies.
|
45 |
+
- A response object that can wrap other WSGI applications and handle
|
46 |
+
streaming data.
|
47 |
+
- A routing system for matching URLs to endpoints and generating URLs
|
48 |
+
for endpoints, with an extensible system for capturing variables
|
49 |
+
from URLs.
|
50 |
+
- HTTP utilities to handle entity tags, cache control, dates, user
|
51 |
+
agents, cookies, files, and more.
|
52 |
+
- A threaded WSGI server for use while developing applications
|
53 |
+
locally.
|
54 |
+
- A test client for simulating HTTP requests during testing without
|
55 |
+
requiring running a server.
|
56 |
+
|
57 |
+
Werkzeug doesn't enforce any dependencies. It is up to the developer to
|
58 |
+
choose a template engine, database adapter, and even how to handle
|
59 |
+
requests. It can be used to build all sorts of end user applications
|
60 |
+
such as blogs, wikis, or bulletin boards.
|
61 |
+
|
62 |
+
[Flask][] wraps Werkzeug, using it to handle the details of WSGI while
|
63 |
+
providing more structure and patterns for defining powerful
|
64 |
+
applications.
|
65 |
+
|
66 |
+
[WSGI]: https://wsgi.readthedocs.io/en/latest/
|
67 |
+
[Flask]: https://www.palletsprojects.com/p/flask/
|
68 |
+
|
69 |
+
|
70 |
+
## A Simple Example
|
71 |
+
|
72 |
+
```python
|
73 |
+
# save this as app.py
|
74 |
+
from werkzeug.wrappers import Request, Response
|
75 |
+
|
76 |
+
@Request.application
|
77 |
+
def application(request: Request) -> Response:
|
78 |
+
return Response("Hello, World!")
|
79 |
+
|
80 |
+
if __name__ == "__main__":
|
81 |
+
from werkzeug.serving import run_simple
|
82 |
+
run_simple("127.0.0.1", 5000, application)
|
83 |
+
```
|
84 |
+
|
85 |
+
```
|
86 |
+
$ python -m app
|
87 |
+
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
|
88 |
+
```
|
89 |
+
|
90 |
+
|
91 |
+
## Donate
|
92 |
+
|
93 |
+
The Pallets organization develops and supports Werkzeug and other
|
94 |
+
popular packages. In order to grow the community of contributors and
|
95 |
+
users, and allow the maintainers to devote more time to the projects,
|
96 |
+
[please donate today][].
|
97 |
+
|
98 |
+
[please donate today]: https://palletsprojects.com/donate
|
99 |
+
|
MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/RECORD
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
werkzeug-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
2 |
+
werkzeug-3.0.3.dist-info/LICENSE.txt,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
|
3 |
+
werkzeug-3.0.3.dist-info/METADATA,sha256=q6dwCfUWf4-0FFck9mU8Yfcy2DG29TXKG3u0YSsorLU,3682
|
4 |
+
werkzeug-3.0.3.dist-info/RECORD,,
|
5 |
+
werkzeug-3.0.3.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
6 |
+
werkzeug/__init__.py,sha256=HX_PSY5E2vtVlD3R4YblwBRCjg7j3Tlm3LASbYqOSkU,727
|
7 |
+
werkzeug/__pycache__/__init__.cpython-39.pyc,,
|
8 |
+
werkzeug/__pycache__/_internal.cpython-39.pyc,,
|
9 |
+
werkzeug/__pycache__/_reloader.cpython-39.pyc,,
|
10 |
+
werkzeug/__pycache__/exceptions.cpython-39.pyc,,
|
11 |
+
werkzeug/__pycache__/formparser.cpython-39.pyc,,
|
12 |
+
werkzeug/__pycache__/http.cpython-39.pyc,,
|
13 |
+
werkzeug/__pycache__/local.cpython-39.pyc,,
|
14 |
+
werkzeug/__pycache__/security.cpython-39.pyc,,
|
15 |
+
werkzeug/__pycache__/serving.cpython-39.pyc,,
|
16 |
+
werkzeug/__pycache__/test.cpython-39.pyc,,
|
17 |
+
werkzeug/__pycache__/testapp.cpython-39.pyc,,
|
18 |
+
werkzeug/__pycache__/urls.cpython-39.pyc,,
|
19 |
+
werkzeug/__pycache__/user_agent.cpython-39.pyc,,
|
20 |
+
werkzeug/__pycache__/utils.cpython-39.pyc,,
|
21 |
+
werkzeug/__pycache__/wsgi.cpython-39.pyc,,
|
22 |
+
werkzeug/_internal.py,sha256=su1olkbHMkzt0VKcEkPLCha8sdVzXNBuqW6YVpp8GHg,5545
|
23 |
+
werkzeug/_reloader.py,sha256=YB1h2hopXAsnIVn2LIgt1lkEJLlTLE6qk2zlvGBCd3U,15082
|
24 |
+
werkzeug/datastructures/__init__.py,sha256=yzBdOT9DdK3nraNG49pA3bVsvtPPLx2-t2N8ZmuAd9w,1900
|
25 |
+
werkzeug/datastructures/__pycache__/__init__.cpython-39.pyc,,
|
26 |
+
werkzeug/datastructures/__pycache__/accept.cpython-39.pyc,,
|
27 |
+
werkzeug/datastructures/__pycache__/auth.cpython-39.pyc,,
|
28 |
+
werkzeug/datastructures/__pycache__/cache_control.cpython-39.pyc,,
|
29 |
+
werkzeug/datastructures/__pycache__/csp.cpython-39.pyc,,
|
30 |
+
werkzeug/datastructures/__pycache__/etag.cpython-39.pyc,,
|
31 |
+
werkzeug/datastructures/__pycache__/file_storage.cpython-39.pyc,,
|
32 |
+
werkzeug/datastructures/__pycache__/headers.cpython-39.pyc,,
|
33 |
+
werkzeug/datastructures/__pycache__/mixins.cpython-39.pyc,,
|
34 |
+
werkzeug/datastructures/__pycache__/range.cpython-39.pyc,,
|
35 |
+
werkzeug/datastructures/__pycache__/structures.cpython-39.pyc,,
|
36 |
+
werkzeug/datastructures/accept.py,sha256=CuCvBAxNzbt4QUb17rH986vvOVGURFUjo0DX2PQy_yI,10670
|
37 |
+
werkzeug/datastructures/accept.pyi,sha256=6P114gncjZoy-i_n_3OQy2nJVwjEAIe7PcBxKYqCEfc,1917
|
38 |
+
werkzeug/datastructures/auth.py,sha256=tZz0wZ1sIpIcAQoEAVhrUvy8M3kqKvIytmvGvwkAdxo,10021
|
39 |
+
werkzeug/datastructures/cache_control.py,sha256=RTUipZev50s-1TAn2rYGZrytm_6IOIxQd67fkR5bNF0,6043
|
40 |
+
werkzeug/datastructures/cache_control.pyi,sha256=NI5myF8f4yzgiqOHJANgp6XtT8SGCWI_GBp5JuH3NIs,3870
|
41 |
+
werkzeug/datastructures/csp.py,sha256=DAOAO266LK0JKbvlG80bbkAgfrNsnU9HBoz-FdIYNdo,3244
|
42 |
+
werkzeug/datastructures/csp.pyi,sha256=AmDWiZU4rrJA4SZmyMNI1L5PLdIfJsI5Li9r5lE1q6M,5765
|
43 |
+
werkzeug/datastructures/etag.py,sha256=JsyI-yXayF-hQu26MyFzbHFIZsaQ6odj3RZO_jF-_cc,2913
|
44 |
+
werkzeug/datastructures/etag.pyi,sha256=N9cuUBrZnxHmsbW0BBmjKW-djNY7WKbI6t_WopB8Zo0,1047
|
45 |
+
werkzeug/datastructures/file_storage.py,sha256=ePeMtr65s_1_sunXMv_SBOiFof5CX5BepYv5_W16fZk,6184
|
46 |
+
werkzeug/datastructures/file_storage.pyi,sha256=PvUx7s2U3ifIf2YxMUhFtZFdkLFderInKG1U3VWwM9E,1457
|
47 |
+
werkzeug/datastructures/headers.py,sha256=97-P-LgzterxEwxLbQsBEGiZpCOAXzZ7fExXXd4uH-o,17286
|
48 |
+
werkzeug/datastructures/headers.pyi,sha256=66Gh9DbD8QNpLRBOuer4DMCj12csddHrcgxiJPLE5n8,4237
|
49 |
+
werkzeug/datastructures/mixins.py,sha256=-IQSQ70UOMQlqtJEIyyhplOd4obaTOfzGvka-cunCtM,5337
|
50 |
+
werkzeug/datastructures/mixins.pyi,sha256=Axe16elbs9zSOK9IuXIGs08ukgqSSPCxXFEjB_ACYSM,4189
|
51 |
+
werkzeug/datastructures/range.py,sha256=JXSDPseG7iH5giJp3R1SnQC_SqQp634M8Iv6QTsbTxM,5669
|
52 |
+
werkzeug/datastructures/range.pyi,sha256=bsM61iNp86gT2lyN0F_Dqg8xsnfPerdmElipuHppiJQ,1792
|
53 |
+
werkzeug/datastructures/structures.py,sha256=8nRqvwHM8moZj_fEaxOqF-N7lguoXgnNJeT2l9LX7xA,31917
|
54 |
+
werkzeug/datastructures/structures.pyi,sha256=9NeGm8NDS-x3XmE2ZP9676tKvQfo5G9GGvIlfV4v3aY,8237
|
55 |
+
werkzeug/debug/__init__.py,sha256=QyiMgAHIDo7Is564apzqf5YuAw7kccQNQ7-EYPfrv8k,19838
|
56 |
+
werkzeug/debug/__pycache__/__init__.cpython-39.pyc,,
|
57 |
+
werkzeug/debug/__pycache__/console.cpython-39.pyc,,
|
58 |
+
werkzeug/debug/__pycache__/repr.cpython-39.pyc,,
|
59 |
+
werkzeug/debug/__pycache__/tbtools.cpython-39.pyc,,
|
60 |
+
werkzeug/debug/console.py,sha256=t4hZ0Qg1p6Uu2MWimqoMDi7S3WYZvLMjnc8v_dPaxAo,6089
|
61 |
+
werkzeug/debug/repr.py,sha256=iHMYny8whiiMDasvUqj0nm4-1VHVvwe697KleiZVK1s,9303
|
62 |
+
werkzeug/debug/shared/ICON_LICENSE.md,sha256=DhA6Y1gUl5Jwfg0NFN9Rj4VWITt8tUx0IvdGf0ux9-s,222
|
63 |
+
werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507
|
64 |
+
werkzeug/debug/shared/debugger.js,sha256=nkYRd_yUc23roybb4i4xs3jMQxr0cebQ5HR75_zxpdk,10544
|
65 |
+
werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191
|
66 |
+
werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200
|
67 |
+
werkzeug/debug/shared/style.css,sha256=-xSxzUEZGw_IqlDR5iZxitNl8LQUjBM-_Y4UAvXVH8g,6078
|
68 |
+
werkzeug/debug/tbtools.py,sha256=DN1JDaDV4J_BAGf9ItOr1bs6HJly7iFHiTpWEDAiYCU,13265
|
69 |
+
werkzeug/exceptions.py,sha256=SX3MUTqvWVyA9SnfMPxowNPu5beR9DyrmbUJ4AD2XT0,26160
|
70 |
+
werkzeug/formparser.py,sha256=BabxEz6Bu1Q1BlKUwkmllb7FN4QBn_5eX2K9tHPr80s,15420
|
71 |
+
werkzeug/http.py,sha256=x_x5xj9FcJyS5rurfnF0KOl0csyy4YlV_ur4hb1IZ2w,43546
|
72 |
+
werkzeug/local.py,sha256=KUFuAm8BAayQouzVg0MGqW_hiwY8Z_lY5l7d1Scvsx8,22492
|
73 |
+
werkzeug/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
74 |
+
werkzeug/middleware/__pycache__/__init__.cpython-39.pyc,,
|
75 |
+
werkzeug/middleware/__pycache__/dispatcher.cpython-39.pyc,,
|
76 |
+
werkzeug/middleware/__pycache__/http_proxy.cpython-39.pyc,,
|
77 |
+
werkzeug/middleware/__pycache__/lint.cpython-39.pyc,,
|
78 |
+
werkzeug/middleware/__pycache__/profiler.cpython-39.pyc,,
|
79 |
+
werkzeug/middleware/__pycache__/proxy_fix.cpython-39.pyc,,
|
80 |
+
werkzeug/middleware/__pycache__/shared_data.cpython-39.pyc,,
|
81 |
+
werkzeug/middleware/dispatcher.py,sha256=zWN5_lqJr_sc9UDv-PPoSlDHN_zR33z6B74F_4Cxpo8,2602
|
82 |
+
werkzeug/middleware/http_proxy.py,sha256=sdk-V6GoZ6aMny-D0QNKNf5MWD2OTO3AGbBg6upp4Hc,7834
|
83 |
+
werkzeug/middleware/lint.py,sha256=lwsZhyDNTnsNr4D8dqsgG8Akp7YP9D_X49SCiZucE04,14478
|
84 |
+
werkzeug/middleware/profiler.py,sha256=1ZAHlDeYNdhgp8THOXkV5lgmcLl307phAr2Ufy30-lY,5562
|
85 |
+
werkzeug/middleware/proxy_fix.py,sha256=n-HW-MRWJquCIhmqiZKoGdbbEeHuWJqPRHhFpuj4pzY,6755
|
86 |
+
werkzeug/middleware/shared_data.py,sha256=a6gT17zipdiYhxvGb-cKnayDk8VZi04CJwxf1fr2Is0,9499
|
87 |
+
werkzeug/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88 |
+
werkzeug/routing/__init__.py,sha256=d8TRxsk24IWu2BdoOYUfL--deolHwiGVCBJqLoEe3YM,4820
|
89 |
+
werkzeug/routing/__pycache__/__init__.cpython-39.pyc,,
|
90 |
+
werkzeug/routing/__pycache__/converters.cpython-39.pyc,,
|
91 |
+
werkzeug/routing/__pycache__/exceptions.cpython-39.pyc,,
|
92 |
+
werkzeug/routing/__pycache__/map.cpython-39.pyc,,
|
93 |
+
werkzeug/routing/__pycache__/matcher.cpython-39.pyc,,
|
94 |
+
werkzeug/routing/__pycache__/rules.cpython-39.pyc,,
|
95 |
+
werkzeug/routing/converters.py,sha256=iqpee_mAjr1oGbq0etujYF9PiDv5U7DgNkARHXnMId0,7297
|
96 |
+
werkzeug/routing/exceptions.py,sha256=wNBiUmUk4OtFOpbdDSr7KKKUjH7yn84JqwBicUup8p8,4846
|
97 |
+
werkzeug/routing/map.py,sha256=mEXlHOyinkg1Jtx5L0UDYsvoX4eVLiEuEVQzD5LVAz8,36515
|
98 |
+
werkzeug/routing/matcher.py,sha256=nfBbl37eGAkZ1dQlumshFcPuyfggmFjPuSSQOE6GuYs,7849
|
99 |
+
werkzeug/routing/rules.py,sha256=rc7FcnN_nQ_k8fzgLYjnoU59WNgShhrqgeB2h7dhFIA,32133
|
100 |
+
werkzeug/sansio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
101 |
+
werkzeug/sansio/__pycache__/__init__.cpython-39.pyc,,
|
102 |
+
werkzeug/sansio/__pycache__/http.cpython-39.pyc,,
|
103 |
+
werkzeug/sansio/__pycache__/multipart.cpython-39.pyc,,
|
104 |
+
werkzeug/sansio/__pycache__/request.cpython-39.pyc,,
|
105 |
+
werkzeug/sansio/__pycache__/response.cpython-39.pyc,,
|
106 |
+
werkzeug/sansio/__pycache__/utils.cpython-39.pyc,,
|
107 |
+
werkzeug/sansio/http.py,sha256=_5fVKoogLUyNH5O2BnKty6dFB1p4REBZieJ4vYoOUOA,5370
|
108 |
+
werkzeug/sansio/multipart.py,sha256=u_XLs68tvP2AO704Yq5zZg7ZN0A33SQaZfQE40gsduo,11490
|
109 |
+
werkzeug/sansio/request.py,sha256=MI59ROX1P_Y6F4FkCLjaV9hwPEXE7aTTqaVphiTw4UA,19983
|
110 |
+
werkzeug/sansio/response.py,sha256=uhKYuDy5-Q5v0Mk5VIxiF-Xob9vfGdDzWiJG7J7MYYc,27585
|
111 |
+
werkzeug/sansio/utils.py,sha256=Y7zkEmIvBLtVvgwSdtBhFpGqCclBtYx7GUhckiRSyhI,4957
|
112 |
+
werkzeug/security.py,sha256=SrUfgJhGzW_Ex7qjcBINRGcfWdikaiponA5bsps4kLA,5376
|
113 |
+
werkzeug/serving.py,sha256=l8LBIbbvDYPsvKNEB1KsB-1cW7KB0Yhc3YvBDlmXTyM,39531
|
114 |
+
werkzeug/test.py,sha256=kMEWtC_bZ5LqvBya-Pvtq1Jvtb4RR_t7pBp27_4JpJo,52782
|
115 |
+
werkzeug/testapp.py,sha256=5_IS5Dh_WfWfNcTLmbydj01lomgcKA_4l9PPCNZnmdI,6332
|
116 |
+
werkzeug/urls.py,sha256=XyNKwHvK5IC37-wuIDMYWkiCJ3yLTLGv7wn2GF3ndqI,6430
|
117 |
+
werkzeug/user_agent.py,sha256=lSlLYKCcbzCUSkbdAoO8zPk2UR-8Mdn6iu_iA2kYPBA,1416
|
118 |
+
werkzeug/utils.py,sha256=6iV_-JdFaLXG6bCR3FMSMyUY0HCnsdzlKirANavAXkk,24699
|
119 |
+
werkzeug/wrappers/__init__.py,sha256=b78jCM8x96kJUGLZ5FYFR3zlK-3pnFAmP9RJIGU0ses,138
|
120 |
+
werkzeug/wrappers/__pycache__/__init__.cpython-39.pyc,,
|
121 |
+
werkzeug/wrappers/__pycache__/request.cpython-39.pyc,,
|
122 |
+
werkzeug/wrappers/__pycache__/response.cpython-39.pyc,,
|
123 |
+
werkzeug/wrappers/request.py,sha256=YygiRF1cu5fypJaGsib_ntGNIFReCnW1ONoDurKXBek,24661
|
124 |
+
werkzeug/wrappers/response.py,sha256=u6zg7VpNYrCeEjpIgf8VqgfaSi9yR_9wi9ly2uudglg,32459
|
125 |
+
werkzeug/wsgi.py,sha256=P7jB0VpG6X6miies4uk7Zgm7NVm4Yz8Ra6Inr5q_FMs,20894
|
MLPY/Lib/site-packages/werkzeug-3.0.3.dist-info/WHEEL
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Wheel-Version: 1.0
|
2 |
+
Generator: flit 3.9.0
|
3 |
+
Root-Is-Purelib: true
|
4 |
+
Tag: py3-none-any
|
MLPY/Lib/site-packages/werkzeug/__init__.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import typing as t
|
4 |
+
|
5 |
+
from .serving import run_simple as run_simple
|
6 |
+
from .test import Client as Client
|
7 |
+
from .wrappers import Request as Request
|
8 |
+
from .wrappers import Response as Response
|
9 |
+
|
10 |
+
|
11 |
+
def __getattr__(name: str) -> t.Any:
|
12 |
+
if name == "__version__":
|
13 |
+
import importlib.metadata
|
14 |
+
import warnings
|
15 |
+
|
16 |
+
warnings.warn(
|
17 |
+
"The '__version__' attribute is deprecated and will be removed in"
|
18 |
+
" Werkzeug 3.1. Use feature detection or"
|
19 |
+
" 'importlib.metadata.version(\"werkzeug\")' instead.",
|
20 |
+
DeprecationWarning,
|
21 |
+
stacklevel=2,
|
22 |
+
)
|
23 |
+
return importlib.metadata.version("werkzeug")
|
24 |
+
|
25 |
+
raise AttributeError(name)
|
MLPY/Lib/site-packages/werkzeug/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (893 Bytes). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/_internal.cpython-39.pyc
ADDED
Binary file (6.75 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/_reloader.cpython-39.pyc
ADDED
Binary file (12.4 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/exceptions.cpython-39.pyc
ADDED
Binary file (27.7 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/formparser.cpython-39.pyc
ADDED
Binary file (12.3 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/http.cpython-39.pyc
ADDED
Binary file (37.7 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/local.cpython-39.pyc
ADDED
Binary file (20.6 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/security.cpython-39.pyc
ADDED
Binary file (5.25 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/serving.cpython-39.pyc
ADDED
Binary file (29.7 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/test.cpython-39.pyc
ADDED
Binary file (42.2 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/testapp.cpython-39.pyc
ADDED
Binary file (6.53 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/urls.cpython-39.pyc
ADDED
Binary file (5.71 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/user_agent.cpython-39.pyc
ADDED
Binary file (1.8 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/utils.cpython-39.pyc
ADDED
Binary file (21.9 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/__pycache__/wsgi.cpython-39.pyc
ADDED
Binary file (19.6 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/_internal.py
ADDED
@@ -0,0 +1,211 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import logging
|
4 |
+
import re
|
5 |
+
import sys
|
6 |
+
import typing as t
|
7 |
+
from datetime import datetime
|
8 |
+
from datetime import timezone
|
9 |
+
|
10 |
+
if t.TYPE_CHECKING:
|
11 |
+
from _typeshed.wsgi import WSGIEnvironment
|
12 |
+
|
13 |
+
from .wrappers.request import Request
|
14 |
+
|
15 |
+
_logger: logging.Logger | None = None
|
16 |
+
|
17 |
+
|
18 |
+
class _Missing:
|
19 |
+
def __repr__(self) -> str:
|
20 |
+
return "no value"
|
21 |
+
|
22 |
+
def __reduce__(self) -> str:
|
23 |
+
return "_missing"
|
24 |
+
|
25 |
+
|
26 |
+
_missing = _Missing()
|
27 |
+
|
28 |
+
|
29 |
+
def _wsgi_decoding_dance(s: str) -> str:
|
30 |
+
return s.encode("latin1").decode(errors="replace")
|
31 |
+
|
32 |
+
|
33 |
+
def _wsgi_encoding_dance(s: str) -> str:
|
34 |
+
return s.encode().decode("latin1")
|
35 |
+
|
36 |
+
|
37 |
+
def _get_environ(obj: WSGIEnvironment | Request) -> WSGIEnvironment:
|
38 |
+
env = getattr(obj, "environ", obj)
|
39 |
+
assert isinstance(
|
40 |
+
env, dict
|
41 |
+
), f"{type(obj).__name__!r} is not a WSGI environment (has to be a dict)"
|
42 |
+
return env
|
43 |
+
|
44 |
+
|
45 |
+
def _has_level_handler(logger: logging.Logger) -> bool:
|
46 |
+
"""Check if there is a handler in the logging chain that will handle
|
47 |
+
the given logger's effective level.
|
48 |
+
"""
|
49 |
+
level = logger.getEffectiveLevel()
|
50 |
+
current = logger
|
51 |
+
|
52 |
+
while current:
|
53 |
+
if any(handler.level <= level for handler in current.handlers):
|
54 |
+
return True
|
55 |
+
|
56 |
+
if not current.propagate:
|
57 |
+
break
|
58 |
+
|
59 |
+
current = current.parent # type: ignore
|
60 |
+
|
61 |
+
return False
|
62 |
+
|
63 |
+
|
64 |
+
class _ColorStreamHandler(logging.StreamHandler): # type: ignore[type-arg]
|
65 |
+
"""On Windows, wrap stream with Colorama for ANSI style support."""
|
66 |
+
|
67 |
+
def __init__(self) -> None:
|
68 |
+
try:
|
69 |
+
import colorama
|
70 |
+
except ImportError:
|
71 |
+
stream = None
|
72 |
+
else:
|
73 |
+
stream = colorama.AnsiToWin32(sys.stderr)
|
74 |
+
|
75 |
+
super().__init__(stream)
|
76 |
+
|
77 |
+
|
78 |
+
def _log(type: str, message: str, *args: t.Any, **kwargs: t.Any) -> None:
|
79 |
+
"""Log a message to the 'werkzeug' logger.
|
80 |
+
|
81 |
+
The logger is created the first time it is needed. If there is no
|
82 |
+
level set, it is set to :data:`logging.INFO`. If there is no handler
|
83 |
+
for the logger's effective level, a :class:`logging.StreamHandler`
|
84 |
+
is added.
|
85 |
+
"""
|
86 |
+
global _logger
|
87 |
+
|
88 |
+
if _logger is None:
|
89 |
+
_logger = logging.getLogger("werkzeug")
|
90 |
+
|
91 |
+
if _logger.level == logging.NOTSET:
|
92 |
+
_logger.setLevel(logging.INFO)
|
93 |
+
|
94 |
+
if not _has_level_handler(_logger):
|
95 |
+
_logger.addHandler(_ColorStreamHandler())
|
96 |
+
|
97 |
+
getattr(_logger, type)(message.rstrip(), *args, **kwargs)
|
98 |
+
|
99 |
+
|
100 |
+
@t.overload
|
101 |
+
def _dt_as_utc(dt: None) -> None: ...
|
102 |
+
|
103 |
+
|
104 |
+
@t.overload
|
105 |
+
def _dt_as_utc(dt: datetime) -> datetime: ...
|
106 |
+
|
107 |
+
|
108 |
+
def _dt_as_utc(dt: datetime | None) -> datetime | None:
|
109 |
+
if dt is None:
|
110 |
+
return dt
|
111 |
+
|
112 |
+
if dt.tzinfo is None:
|
113 |
+
return dt.replace(tzinfo=timezone.utc)
|
114 |
+
elif dt.tzinfo != timezone.utc:
|
115 |
+
return dt.astimezone(timezone.utc)
|
116 |
+
|
117 |
+
return dt
|
118 |
+
|
119 |
+
|
120 |
+
_TAccessorValue = t.TypeVar("_TAccessorValue")
|
121 |
+
|
122 |
+
|
123 |
+
class _DictAccessorProperty(t.Generic[_TAccessorValue]):
|
124 |
+
"""Baseclass for `environ_property` and `header_property`."""
|
125 |
+
|
126 |
+
read_only = False
|
127 |
+
|
128 |
+
def __init__(
|
129 |
+
self,
|
130 |
+
name: str,
|
131 |
+
default: _TAccessorValue | None = None,
|
132 |
+
load_func: t.Callable[[str], _TAccessorValue] | None = None,
|
133 |
+
dump_func: t.Callable[[_TAccessorValue], str] | None = None,
|
134 |
+
read_only: bool | None = None,
|
135 |
+
doc: str | None = None,
|
136 |
+
) -> None:
|
137 |
+
self.name = name
|
138 |
+
self.default = default
|
139 |
+
self.load_func = load_func
|
140 |
+
self.dump_func = dump_func
|
141 |
+
if read_only is not None:
|
142 |
+
self.read_only = read_only
|
143 |
+
self.__doc__ = doc
|
144 |
+
|
145 |
+
def lookup(self, instance: t.Any) -> t.MutableMapping[str, t.Any]:
|
146 |
+
raise NotImplementedError
|
147 |
+
|
148 |
+
@t.overload
|
149 |
+
def __get__(
|
150 |
+
self, instance: None, owner: type
|
151 |
+
) -> _DictAccessorProperty[_TAccessorValue]: ...
|
152 |
+
|
153 |
+
@t.overload
|
154 |
+
def __get__(self, instance: t.Any, owner: type) -> _TAccessorValue: ...
|
155 |
+
|
156 |
+
def __get__(
|
157 |
+
self, instance: t.Any | None, owner: type
|
158 |
+
) -> _TAccessorValue | _DictAccessorProperty[_TAccessorValue]:
|
159 |
+
if instance is None:
|
160 |
+
return self
|
161 |
+
|
162 |
+
storage = self.lookup(instance)
|
163 |
+
|
164 |
+
if self.name not in storage:
|
165 |
+
return self.default # type: ignore
|
166 |
+
|
167 |
+
value = storage[self.name]
|
168 |
+
|
169 |
+
if self.load_func is not None:
|
170 |
+
try:
|
171 |
+
return self.load_func(value)
|
172 |
+
except (ValueError, TypeError):
|
173 |
+
return self.default # type: ignore
|
174 |
+
|
175 |
+
return value # type: ignore
|
176 |
+
|
177 |
+
def __set__(self, instance: t.Any, value: _TAccessorValue) -> None:
|
178 |
+
if self.read_only:
|
179 |
+
raise AttributeError("read only property")
|
180 |
+
|
181 |
+
if self.dump_func is not None:
|
182 |
+
self.lookup(instance)[self.name] = self.dump_func(value)
|
183 |
+
else:
|
184 |
+
self.lookup(instance)[self.name] = value
|
185 |
+
|
186 |
+
def __delete__(self, instance: t.Any) -> None:
|
187 |
+
if self.read_only:
|
188 |
+
raise AttributeError("read only property")
|
189 |
+
|
190 |
+
self.lookup(instance).pop(self.name, None)
|
191 |
+
|
192 |
+
def __repr__(self) -> str:
|
193 |
+
return f"<{type(self).__name__} {self.name}>"
|
194 |
+
|
195 |
+
|
196 |
+
_plain_int_re = re.compile(r"-?\d+", re.ASCII)
|
197 |
+
|
198 |
+
|
199 |
+
def _plain_int(value: str) -> int:
|
200 |
+
"""Parse an int only if it is only ASCII digits and ``-``.
|
201 |
+
|
202 |
+
This disallows ``+``, ``_``, and non-ASCII digits, which are accepted by ``int`` but
|
203 |
+
are not allowed in HTTP header values.
|
204 |
+
|
205 |
+
Any leading or trailing whitespace is stripped
|
206 |
+
"""
|
207 |
+
value = value.strip()
|
208 |
+
if _plain_int_re.fullmatch(value) is None:
|
209 |
+
raise ValueError
|
210 |
+
|
211 |
+
return int(value)
|
MLPY/Lib/site-packages/werkzeug/_reloader.py
ADDED
@@ -0,0 +1,460 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import fnmatch
|
4 |
+
import os
|
5 |
+
import subprocess
|
6 |
+
import sys
|
7 |
+
import threading
|
8 |
+
import time
|
9 |
+
import typing as t
|
10 |
+
from itertools import chain
|
11 |
+
from pathlib import PurePath
|
12 |
+
|
13 |
+
from ._internal import _log
|
14 |
+
|
15 |
+
# The various system prefixes where imports are found. Base values are
|
16 |
+
# different when running in a virtualenv. All reloaders will ignore the
|
17 |
+
# base paths (usually the system installation). The stat reloader won't
|
18 |
+
# scan the virtualenv paths, it will only include modules that are
|
19 |
+
# already imported.
|
20 |
+
_ignore_always = tuple({sys.base_prefix, sys.base_exec_prefix})
|
21 |
+
prefix = {*_ignore_always, sys.prefix, sys.exec_prefix}
|
22 |
+
|
23 |
+
if hasattr(sys, "real_prefix"):
|
24 |
+
# virtualenv < 20
|
25 |
+
prefix.add(sys.real_prefix)
|
26 |
+
|
27 |
+
_stat_ignore_scan = tuple(prefix)
|
28 |
+
del prefix
|
29 |
+
_ignore_common_dirs = {
|
30 |
+
"__pycache__",
|
31 |
+
".git",
|
32 |
+
".hg",
|
33 |
+
".tox",
|
34 |
+
".nox",
|
35 |
+
".pytest_cache",
|
36 |
+
".mypy_cache",
|
37 |
+
}
|
38 |
+
|
39 |
+
|
40 |
+
def _iter_module_paths() -> t.Iterator[str]:
|
41 |
+
"""Find the filesystem paths associated with imported modules."""
|
42 |
+
# List is in case the value is modified by the app while updating.
|
43 |
+
for module in list(sys.modules.values()):
|
44 |
+
name = getattr(module, "__file__", None)
|
45 |
+
|
46 |
+
if name is None or name.startswith(_ignore_always):
|
47 |
+
continue
|
48 |
+
|
49 |
+
while not os.path.isfile(name):
|
50 |
+
# Zip file, find the base file without the module path.
|
51 |
+
old = name
|
52 |
+
name = os.path.dirname(name)
|
53 |
+
|
54 |
+
if name == old: # skip if it was all directories somehow
|
55 |
+
break
|
56 |
+
else:
|
57 |
+
yield name
|
58 |
+
|
59 |
+
|
60 |
+
def _remove_by_pattern(paths: set[str], exclude_patterns: set[str]) -> None:
|
61 |
+
for pattern in exclude_patterns:
|
62 |
+
paths.difference_update(fnmatch.filter(paths, pattern))
|
63 |
+
|
64 |
+
|
65 |
+
def _find_stat_paths(
|
66 |
+
extra_files: set[str], exclude_patterns: set[str]
|
67 |
+
) -> t.Iterable[str]:
|
68 |
+
"""Find paths for the stat reloader to watch. Returns imported
|
69 |
+
module files, Python files under non-system paths. Extra files and
|
70 |
+
Python files under extra directories can also be scanned.
|
71 |
+
|
72 |
+
System paths have to be excluded for efficiency. Non-system paths,
|
73 |
+
such as a project root or ``sys.path.insert``, should be the paths
|
74 |
+
of interest to the user anyway.
|
75 |
+
"""
|
76 |
+
paths = set()
|
77 |
+
|
78 |
+
for path in chain(list(sys.path), extra_files):
|
79 |
+
path = os.path.abspath(path)
|
80 |
+
|
81 |
+
if os.path.isfile(path):
|
82 |
+
# zip file on sys.path, or extra file
|
83 |
+
paths.add(path)
|
84 |
+
continue
|
85 |
+
|
86 |
+
parent_has_py = {os.path.dirname(path): True}
|
87 |
+
|
88 |
+
for root, dirs, files in os.walk(path):
|
89 |
+
# Optimizations: ignore system prefixes, __pycache__ will
|
90 |
+
# have a py or pyc module at the import path, ignore some
|
91 |
+
# common known dirs such as version control and tool caches.
|
92 |
+
if (
|
93 |
+
root.startswith(_stat_ignore_scan)
|
94 |
+
or os.path.basename(root) in _ignore_common_dirs
|
95 |
+
):
|
96 |
+
dirs.clear()
|
97 |
+
continue
|
98 |
+
|
99 |
+
has_py = False
|
100 |
+
|
101 |
+
for name in files:
|
102 |
+
if name.endswith((".py", ".pyc")):
|
103 |
+
has_py = True
|
104 |
+
paths.add(os.path.join(root, name))
|
105 |
+
|
106 |
+
# Optimization: stop scanning a directory if neither it nor
|
107 |
+
# its parent contained Python files.
|
108 |
+
if not (has_py or parent_has_py[os.path.dirname(root)]):
|
109 |
+
dirs.clear()
|
110 |
+
continue
|
111 |
+
|
112 |
+
parent_has_py[root] = has_py
|
113 |
+
|
114 |
+
paths.update(_iter_module_paths())
|
115 |
+
_remove_by_pattern(paths, exclude_patterns)
|
116 |
+
return paths
|
117 |
+
|
118 |
+
|
119 |
+
def _find_watchdog_paths(
|
120 |
+
extra_files: set[str], exclude_patterns: set[str]
|
121 |
+
) -> t.Iterable[str]:
|
122 |
+
"""Find paths for the stat reloader to watch. Looks at the same
|
123 |
+
sources as the stat reloader, but watches everything under
|
124 |
+
directories instead of individual files.
|
125 |
+
"""
|
126 |
+
dirs = set()
|
127 |
+
|
128 |
+
for name in chain(list(sys.path), extra_files):
|
129 |
+
name = os.path.abspath(name)
|
130 |
+
|
131 |
+
if os.path.isfile(name):
|
132 |
+
name = os.path.dirname(name)
|
133 |
+
|
134 |
+
dirs.add(name)
|
135 |
+
|
136 |
+
for name in _iter_module_paths():
|
137 |
+
dirs.add(os.path.dirname(name))
|
138 |
+
|
139 |
+
_remove_by_pattern(dirs, exclude_patterns)
|
140 |
+
return _find_common_roots(dirs)
|
141 |
+
|
142 |
+
|
143 |
+
def _find_common_roots(paths: t.Iterable[str]) -> t.Iterable[str]:
|
144 |
+
root: dict[str, dict[str, t.Any]] = {}
|
145 |
+
|
146 |
+
for chunks in sorted((PurePath(x).parts for x in paths), key=len, reverse=True):
|
147 |
+
node = root
|
148 |
+
|
149 |
+
for chunk in chunks:
|
150 |
+
node = node.setdefault(chunk, {})
|
151 |
+
|
152 |
+
node.clear()
|
153 |
+
|
154 |
+
rv = set()
|
155 |
+
|
156 |
+
def _walk(node: t.Mapping[str, dict[str, t.Any]], path: tuple[str, ...]) -> None:
|
157 |
+
for prefix, child in node.items():
|
158 |
+
_walk(child, path + (prefix,))
|
159 |
+
|
160 |
+
# If there are no more nodes, and a path has been accumulated, add it.
|
161 |
+
# Path may be empty if the "" entry is in sys.path.
|
162 |
+
if not node and path:
|
163 |
+
rv.add(os.path.join(*path))
|
164 |
+
|
165 |
+
_walk(root, ())
|
166 |
+
return rv
|
167 |
+
|
168 |
+
|
169 |
+
def _get_args_for_reloading() -> list[str]:
|
170 |
+
"""Determine how the script was executed, and return the args needed
|
171 |
+
to execute it again in a new process.
|
172 |
+
"""
|
173 |
+
if sys.version_info >= (3, 10):
|
174 |
+
# sys.orig_argv, added in Python 3.10, contains the exact args used to invoke
|
175 |
+
# Python. Still replace argv[0] with sys.executable for accuracy.
|
176 |
+
return [sys.executable, *sys.orig_argv[1:]]
|
177 |
+
|
178 |
+
rv = [sys.executable]
|
179 |
+
py_script = sys.argv[0]
|
180 |
+
args = sys.argv[1:]
|
181 |
+
# Need to look at main module to determine how it was executed.
|
182 |
+
__main__ = sys.modules["__main__"]
|
183 |
+
|
184 |
+
# The value of __package__ indicates how Python was called. It may
|
185 |
+
# not exist if a setuptools script is installed as an egg. It may be
|
186 |
+
# set incorrectly for entry points created with pip on Windows.
|
187 |
+
if getattr(__main__, "__package__", None) is None or (
|
188 |
+
os.name == "nt"
|
189 |
+
and __main__.__package__ == ""
|
190 |
+
and not os.path.exists(py_script)
|
191 |
+
and os.path.exists(f"{py_script}.exe")
|
192 |
+
):
|
193 |
+
# Executed a file, like "python app.py".
|
194 |
+
py_script = os.path.abspath(py_script)
|
195 |
+
|
196 |
+
if os.name == "nt":
|
197 |
+
# Windows entry points have ".exe" extension and should be
|
198 |
+
# called directly.
|
199 |
+
if not os.path.exists(py_script) and os.path.exists(f"{py_script}.exe"):
|
200 |
+
py_script += ".exe"
|
201 |
+
|
202 |
+
if (
|
203 |
+
os.path.splitext(sys.executable)[1] == ".exe"
|
204 |
+
and os.path.splitext(py_script)[1] == ".exe"
|
205 |
+
):
|
206 |
+
rv.pop(0)
|
207 |
+
|
208 |
+
rv.append(py_script)
|
209 |
+
else:
|
210 |
+
# Executed a module, like "python -m werkzeug.serving".
|
211 |
+
if os.path.isfile(py_script):
|
212 |
+
# Rewritten by Python from "-m script" to "/path/to/script.py".
|
213 |
+
py_module = t.cast(str, __main__.__package__)
|
214 |
+
name = os.path.splitext(os.path.basename(py_script))[0]
|
215 |
+
|
216 |
+
if name != "__main__":
|
217 |
+
py_module += f".{name}"
|
218 |
+
else:
|
219 |
+
# Incorrectly rewritten by pydevd debugger from "-m script" to "script".
|
220 |
+
py_module = py_script
|
221 |
+
|
222 |
+
rv.extend(("-m", py_module.lstrip(".")))
|
223 |
+
|
224 |
+
rv.extend(args)
|
225 |
+
return rv
|
226 |
+
|
227 |
+
|
228 |
+
class ReloaderLoop:
|
229 |
+
name = ""
|
230 |
+
|
231 |
+
def __init__(
|
232 |
+
self,
|
233 |
+
extra_files: t.Iterable[str] | None = None,
|
234 |
+
exclude_patterns: t.Iterable[str] | None = None,
|
235 |
+
interval: int | float = 1,
|
236 |
+
) -> None:
|
237 |
+
self.extra_files: set[str] = {os.path.abspath(x) for x in extra_files or ()}
|
238 |
+
self.exclude_patterns: set[str] = set(exclude_patterns or ())
|
239 |
+
self.interval = interval
|
240 |
+
|
241 |
+
def __enter__(self) -> ReloaderLoop:
|
242 |
+
"""Do any setup, then run one step of the watch to populate the
|
243 |
+
initial filesystem state.
|
244 |
+
"""
|
245 |
+
self.run_step()
|
246 |
+
return self
|
247 |
+
|
248 |
+
def __exit__(self, exc_type, exc_val, exc_tb): # type: ignore
|
249 |
+
"""Clean up any resources associated with the reloader."""
|
250 |
+
pass
|
251 |
+
|
252 |
+
def run(self) -> None:
|
253 |
+
"""Continually run the watch step, sleeping for the configured
|
254 |
+
interval after each step.
|
255 |
+
"""
|
256 |
+
while True:
|
257 |
+
self.run_step()
|
258 |
+
time.sleep(self.interval)
|
259 |
+
|
260 |
+
def run_step(self) -> None:
|
261 |
+
"""Run one step for watching the filesystem. Called once to set
|
262 |
+
up initial state, then repeatedly to update it.
|
263 |
+
"""
|
264 |
+
pass
|
265 |
+
|
266 |
+
def restart_with_reloader(self) -> int:
|
267 |
+
"""Spawn a new Python interpreter with the same arguments as the
|
268 |
+
current one, but running the reloader thread.
|
269 |
+
"""
|
270 |
+
while True:
|
271 |
+
_log("info", f" * Restarting with {self.name}")
|
272 |
+
args = _get_args_for_reloading()
|
273 |
+
new_environ = os.environ.copy()
|
274 |
+
new_environ["WERKZEUG_RUN_MAIN"] = "true"
|
275 |
+
exit_code = subprocess.call(args, env=new_environ, close_fds=False)
|
276 |
+
|
277 |
+
if exit_code != 3:
|
278 |
+
return exit_code
|
279 |
+
|
280 |
+
def trigger_reload(self, filename: str) -> None:
|
281 |
+
self.log_reload(filename)
|
282 |
+
sys.exit(3)
|
283 |
+
|
284 |
+
def log_reload(self, filename: str) -> None:
|
285 |
+
filename = os.path.abspath(filename)
|
286 |
+
_log("info", f" * Detected change in {filename!r}, reloading")
|
287 |
+
|
288 |
+
|
289 |
+
class StatReloaderLoop(ReloaderLoop):
|
290 |
+
name = "stat"
|
291 |
+
|
292 |
+
def __enter__(self) -> ReloaderLoop:
|
293 |
+
self.mtimes: dict[str, float] = {}
|
294 |
+
return super().__enter__()
|
295 |
+
|
296 |
+
def run_step(self) -> None:
|
297 |
+
for name in _find_stat_paths(self.extra_files, self.exclude_patterns):
|
298 |
+
try:
|
299 |
+
mtime = os.stat(name).st_mtime
|
300 |
+
except OSError:
|
301 |
+
continue
|
302 |
+
|
303 |
+
old_time = self.mtimes.get(name)
|
304 |
+
|
305 |
+
if old_time is None:
|
306 |
+
self.mtimes[name] = mtime
|
307 |
+
continue
|
308 |
+
|
309 |
+
if mtime > old_time:
|
310 |
+
self.trigger_reload(name)
|
311 |
+
|
312 |
+
|
313 |
+
class WatchdogReloaderLoop(ReloaderLoop):
|
314 |
+
def __init__(self, *args: t.Any, **kwargs: t.Any) -> None:
|
315 |
+
from watchdog.events import EVENT_TYPE_OPENED
|
316 |
+
from watchdog.events import FileModifiedEvent
|
317 |
+
from watchdog.events import PatternMatchingEventHandler
|
318 |
+
from watchdog.observers import Observer
|
319 |
+
|
320 |
+
super().__init__(*args, **kwargs)
|
321 |
+
trigger_reload = self.trigger_reload
|
322 |
+
|
323 |
+
class EventHandler(PatternMatchingEventHandler):
|
324 |
+
def on_any_event(self, event: FileModifiedEvent): # type: ignore
|
325 |
+
if event.event_type == EVENT_TYPE_OPENED:
|
326 |
+
return
|
327 |
+
|
328 |
+
trigger_reload(event.src_path)
|
329 |
+
|
330 |
+
reloader_name = Observer.__name__.lower() # type: ignore[attr-defined]
|
331 |
+
|
332 |
+
if reloader_name.endswith("observer"):
|
333 |
+
reloader_name = reloader_name[:-8]
|
334 |
+
|
335 |
+
self.name = f"watchdog ({reloader_name})"
|
336 |
+
self.observer = Observer()
|
337 |
+
# Extra patterns can be non-Python files, match them in addition
|
338 |
+
# to all Python files in default and extra directories. Ignore
|
339 |
+
# __pycache__ since a change there will always have a change to
|
340 |
+
# the source file (or initial pyc file) as well. Ignore Git and
|
341 |
+
# Mercurial internal changes.
|
342 |
+
extra_patterns = [p for p in self.extra_files if not os.path.isdir(p)]
|
343 |
+
self.event_handler = EventHandler( # type: ignore[no-untyped-call]
|
344 |
+
patterns=["*.py", "*.pyc", "*.zip", *extra_patterns],
|
345 |
+
ignore_patterns=[
|
346 |
+
*[f"*/{d}/*" for d in _ignore_common_dirs],
|
347 |
+
*self.exclude_patterns,
|
348 |
+
],
|
349 |
+
)
|
350 |
+
self.should_reload = False
|
351 |
+
|
352 |
+
def trigger_reload(self, filename: str) -> None:
|
353 |
+
# This is called inside an event handler, which means throwing
|
354 |
+
# SystemExit has no effect.
|
355 |
+
# https://github.com/gorakhargosh/watchdog/issues/294
|
356 |
+
self.should_reload = True
|
357 |
+
self.log_reload(filename)
|
358 |
+
|
359 |
+
def __enter__(self) -> ReloaderLoop:
|
360 |
+
self.watches: dict[str, t.Any] = {}
|
361 |
+
self.observer.start() # type: ignore[no-untyped-call]
|
362 |
+
return super().__enter__()
|
363 |
+
|
364 |
+
def __exit__(self, exc_type, exc_val, exc_tb): # type: ignore
|
365 |
+
self.observer.stop() # type: ignore[no-untyped-call]
|
366 |
+
self.observer.join()
|
367 |
+
|
368 |
+
def run(self) -> None:
|
369 |
+
while not self.should_reload:
|
370 |
+
self.run_step()
|
371 |
+
time.sleep(self.interval)
|
372 |
+
|
373 |
+
sys.exit(3)
|
374 |
+
|
375 |
+
def run_step(self) -> None:
|
376 |
+
to_delete = set(self.watches)
|
377 |
+
|
378 |
+
for path in _find_watchdog_paths(self.extra_files, self.exclude_patterns):
|
379 |
+
if path not in self.watches:
|
380 |
+
try:
|
381 |
+
self.watches[path] = self.observer.schedule( # type: ignore[no-untyped-call]
|
382 |
+
self.event_handler, path, recursive=True
|
383 |
+
)
|
384 |
+
except OSError:
|
385 |
+
# Clear this path from list of watches We don't want
|
386 |
+
# the same error message showing again in the next
|
387 |
+
# iteration.
|
388 |
+
self.watches[path] = None
|
389 |
+
|
390 |
+
to_delete.discard(path)
|
391 |
+
|
392 |
+
for path in to_delete:
|
393 |
+
watch = self.watches.pop(path, None)
|
394 |
+
|
395 |
+
if watch is not None:
|
396 |
+
self.observer.unschedule(watch) # type: ignore[no-untyped-call]
|
397 |
+
|
398 |
+
|
399 |
+
reloader_loops: dict[str, type[ReloaderLoop]] = {
|
400 |
+
"stat": StatReloaderLoop,
|
401 |
+
"watchdog": WatchdogReloaderLoop,
|
402 |
+
}
|
403 |
+
|
404 |
+
try:
|
405 |
+
__import__("watchdog.observers")
|
406 |
+
except ImportError:
|
407 |
+
reloader_loops["auto"] = reloader_loops["stat"]
|
408 |
+
else:
|
409 |
+
reloader_loops["auto"] = reloader_loops["watchdog"]
|
410 |
+
|
411 |
+
|
412 |
+
def ensure_echo_on() -> None:
|
413 |
+
"""Ensure that echo mode is enabled. Some tools such as PDB disable
|
414 |
+
it which causes usability issues after a reload."""
|
415 |
+
# tcgetattr will fail if stdin isn't a tty
|
416 |
+
if sys.stdin is None or not sys.stdin.isatty():
|
417 |
+
return
|
418 |
+
|
419 |
+
try:
|
420 |
+
import termios
|
421 |
+
except ImportError:
|
422 |
+
return
|
423 |
+
|
424 |
+
attributes = termios.tcgetattr(sys.stdin)
|
425 |
+
|
426 |
+
if not attributes[3] & termios.ECHO:
|
427 |
+
attributes[3] |= termios.ECHO
|
428 |
+
termios.tcsetattr(sys.stdin, termios.TCSANOW, attributes)
|
429 |
+
|
430 |
+
|
431 |
+
def run_with_reloader(
|
432 |
+
main_func: t.Callable[[], None],
|
433 |
+
extra_files: t.Iterable[str] | None = None,
|
434 |
+
exclude_patterns: t.Iterable[str] | None = None,
|
435 |
+
interval: int | float = 1,
|
436 |
+
reloader_type: str = "auto",
|
437 |
+
) -> None:
|
438 |
+
"""Run the given function in an independent Python interpreter."""
|
439 |
+
import signal
|
440 |
+
|
441 |
+
signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
|
442 |
+
reloader = reloader_loops[reloader_type](
|
443 |
+
extra_files=extra_files, exclude_patterns=exclude_patterns, interval=interval
|
444 |
+
)
|
445 |
+
|
446 |
+
try:
|
447 |
+
if os.environ.get("WERKZEUG_RUN_MAIN") == "true":
|
448 |
+
ensure_echo_on()
|
449 |
+
t = threading.Thread(target=main_func, args=())
|
450 |
+
t.daemon = True
|
451 |
+
|
452 |
+
# Enter the reloader to set up initial state, then start
|
453 |
+
# the app thread and reloader update loop.
|
454 |
+
with reloader:
|
455 |
+
t.start()
|
456 |
+
reloader.run()
|
457 |
+
else:
|
458 |
+
sys.exit(reloader.restart_with_reloader())
|
459 |
+
except KeyboardInterrupt:
|
460 |
+
pass
|
MLPY/Lib/site-packages/werkzeug/datastructures/__init__.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .accept import Accept as Accept
|
2 |
+
from .accept import CharsetAccept as CharsetAccept
|
3 |
+
from .accept import LanguageAccept as LanguageAccept
|
4 |
+
from .accept import MIMEAccept as MIMEAccept
|
5 |
+
from .auth import Authorization as Authorization
|
6 |
+
from .auth import WWWAuthenticate as WWWAuthenticate
|
7 |
+
from .cache_control import RequestCacheControl as RequestCacheControl
|
8 |
+
from .cache_control import ResponseCacheControl as ResponseCacheControl
|
9 |
+
from .csp import ContentSecurityPolicy as ContentSecurityPolicy
|
10 |
+
from .etag import ETags as ETags
|
11 |
+
from .file_storage import FileMultiDict as FileMultiDict
|
12 |
+
from .file_storage import FileStorage as FileStorage
|
13 |
+
from .headers import EnvironHeaders as EnvironHeaders
|
14 |
+
from .headers import Headers as Headers
|
15 |
+
from .mixins import ImmutableDictMixin as ImmutableDictMixin
|
16 |
+
from .mixins import ImmutableHeadersMixin as ImmutableHeadersMixin
|
17 |
+
from .mixins import ImmutableListMixin as ImmutableListMixin
|
18 |
+
from .mixins import ImmutableMultiDictMixin as ImmutableMultiDictMixin
|
19 |
+
from .mixins import UpdateDictMixin as UpdateDictMixin
|
20 |
+
from .range import ContentRange as ContentRange
|
21 |
+
from .range import IfRange as IfRange
|
22 |
+
from .range import Range as Range
|
23 |
+
from .structures import CallbackDict as CallbackDict
|
24 |
+
from .structures import CombinedMultiDict as CombinedMultiDict
|
25 |
+
from .structures import HeaderSet as HeaderSet
|
26 |
+
from .structures import ImmutableDict as ImmutableDict
|
27 |
+
from .structures import ImmutableList as ImmutableList
|
28 |
+
from .structures import ImmutableMultiDict as ImmutableMultiDict
|
29 |
+
from .structures import ImmutableOrderedMultiDict as ImmutableOrderedMultiDict
|
30 |
+
from .structures import ImmutableTypeConversionDict as ImmutableTypeConversionDict
|
31 |
+
from .structures import iter_multi_items as iter_multi_items
|
32 |
+
from .structures import MultiDict as MultiDict
|
33 |
+
from .structures import OrderedMultiDict as OrderedMultiDict
|
34 |
+
from .structures import TypeConversionDict as TypeConversionDict
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (1.53 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-39.pyc
ADDED
Binary file (10.6 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-39.pyc
ADDED
Binary file (10.4 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-39.pyc
ADDED
Binary file (6.54 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-39.pyc
ADDED
Binary file (4.11 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-39.pyc
ADDED
Binary file (3.91 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-39.pyc
ADDED
Binary file (6.01 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-39.pyc
ADDED
Binary file (17.7 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-39.pyc
ADDED
Binary file (9.54 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/range.cpython-39.pyc
ADDED
Binary file (6.05 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-39.pyc
ADDED
Binary file (36.4 kB). View file
|
|
MLPY/Lib/site-packages/werkzeug/datastructures/accept.py
ADDED
@@ -0,0 +1,326 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import codecs
|
4 |
+
import re
|
5 |
+
|
6 |
+
from .structures import ImmutableList
|
7 |
+
|
8 |
+
|
9 |
+
class Accept(ImmutableList):
|
10 |
+
"""An :class:`Accept` object is just a list subclass for lists of
|
11 |
+
``(value, quality)`` tuples. It is automatically sorted by specificity
|
12 |
+
and quality.
|
13 |
+
|
14 |
+
All :class:`Accept` objects work similar to a list but provide extra
|
15 |
+
functionality for working with the data. Containment checks are
|
16 |
+
normalized to the rules of that header:
|
17 |
+
|
18 |
+
>>> a = CharsetAccept([('ISO-8859-1', 1), ('utf-8', 0.7)])
|
19 |
+
>>> a.best
|
20 |
+
'ISO-8859-1'
|
21 |
+
>>> 'iso-8859-1' in a
|
22 |
+
True
|
23 |
+
>>> 'UTF8' in a
|
24 |
+
True
|
25 |
+
>>> 'utf7' in a
|
26 |
+
False
|
27 |
+
|
28 |
+
To get the quality for an item you can use normal item lookup:
|
29 |
+
|
30 |
+
>>> print a['utf-8']
|
31 |
+
0.7
|
32 |
+
>>> a['utf7']
|
33 |
+
0
|
34 |
+
|
35 |
+
.. versionchanged:: 0.5
|
36 |
+
:class:`Accept` objects are forced immutable now.
|
37 |
+
|
38 |
+
.. versionchanged:: 1.0.0
|
39 |
+
:class:`Accept` internal values are no longer ordered
|
40 |
+
alphabetically for equal quality tags. Instead the initial
|
41 |
+
order is preserved.
|
42 |
+
|
43 |
+
"""
|
44 |
+
|
45 |
+
def __init__(self, values=()):
|
46 |
+
if values is None:
|
47 |
+
list.__init__(self)
|
48 |
+
self.provided = False
|
49 |
+
elif isinstance(values, Accept):
|
50 |
+
self.provided = values.provided
|
51 |
+
list.__init__(self, values)
|
52 |
+
else:
|
53 |
+
self.provided = True
|
54 |
+
values = sorted(
|
55 |
+
values, key=lambda x: (self._specificity(x[0]), x[1]), reverse=True
|
56 |
+
)
|
57 |
+
list.__init__(self, values)
|
58 |
+
|
59 |
+
def _specificity(self, value):
|
60 |
+
"""Returns a tuple describing the value's specificity."""
|
61 |
+
return (value != "*",)
|
62 |
+
|
63 |
+
def _value_matches(self, value, item):
|
64 |
+
"""Check if a value matches a given accept item."""
|
65 |
+
return item == "*" or item.lower() == value.lower()
|
66 |
+
|
67 |
+
def __getitem__(self, key):
|
68 |
+
"""Besides index lookup (getting item n) you can also pass it a string
|
69 |
+
to get the quality for the item. If the item is not in the list, the
|
70 |
+
returned quality is ``0``.
|
71 |
+
"""
|
72 |
+
if isinstance(key, str):
|
73 |
+
return self.quality(key)
|
74 |
+
return list.__getitem__(self, key)
|
75 |
+
|
76 |
+
def quality(self, key):
|
77 |
+
"""Returns the quality of the key.
|
78 |
+
|
79 |
+
.. versionadded:: 0.6
|
80 |
+
In previous versions you had to use the item-lookup syntax
|
81 |
+
(eg: ``obj[key]`` instead of ``obj.quality(key)``)
|
82 |
+
"""
|
83 |
+
for item, quality in self:
|
84 |
+
if self._value_matches(key, item):
|
85 |
+
return quality
|
86 |
+
return 0
|
87 |
+
|
88 |
+
def __contains__(self, value):
|
89 |
+
for item, _quality in self:
|
90 |
+
if self._value_matches(value, item):
|
91 |
+
return True
|
92 |
+
return False
|
93 |
+
|
94 |
+
def __repr__(self):
|
95 |
+
pairs_str = ", ".join(f"({x!r}, {y})" for x, y in self)
|
96 |
+
return f"{type(self).__name__}([{pairs_str}])"
|
97 |
+
|
98 |
+
def index(self, key):
|
99 |
+
"""Get the position of an entry or raise :exc:`ValueError`.
|
100 |
+
|
101 |
+
:param key: The key to be looked up.
|
102 |
+
|
103 |
+
.. versionchanged:: 0.5
|
104 |
+
This used to raise :exc:`IndexError`, which was inconsistent
|
105 |
+
with the list API.
|
106 |
+
"""
|
107 |
+
if isinstance(key, str):
|
108 |
+
for idx, (item, _quality) in enumerate(self):
|
109 |
+
if self._value_matches(key, item):
|
110 |
+
return idx
|
111 |
+
raise ValueError(key)
|
112 |
+
return list.index(self, key)
|
113 |
+
|
114 |
+
def find(self, key):
|
115 |
+
"""Get the position of an entry or return -1.
|
116 |
+
|
117 |
+
:param key: The key to be looked up.
|
118 |
+
"""
|
119 |
+
try:
|
120 |
+
return self.index(key)
|
121 |
+
except ValueError:
|
122 |
+
return -1
|
123 |
+
|
124 |
+
def values(self):
|
125 |
+
"""Iterate over all values."""
|
126 |
+
for item in self:
|
127 |
+
yield item[0]
|
128 |
+
|
129 |
+
def to_header(self):
|
130 |
+
"""Convert the header set into an HTTP header string."""
|
131 |
+
result = []
|
132 |
+
for value, quality in self:
|
133 |
+
if quality != 1:
|
134 |
+
value = f"{value};q={quality}"
|
135 |
+
result.append(value)
|
136 |
+
return ",".join(result)
|
137 |
+
|
138 |
+
def __str__(self):
|
139 |
+
return self.to_header()
|
140 |
+
|
141 |
+
def _best_single_match(self, match):
|
142 |
+
for client_item, quality in self:
|
143 |
+
if self._value_matches(match, client_item):
|
144 |
+
# self is sorted by specificity descending, we can exit
|
145 |
+
return client_item, quality
|
146 |
+
return None
|
147 |
+
|
148 |
+
def best_match(self, matches, default=None):
|
149 |
+
"""Returns the best match from a list of possible matches based
|
150 |
+
on the specificity and quality of the client. If two items have the
|
151 |
+
same quality and specificity, the one is returned that comes first.
|
152 |
+
|
153 |
+
:param matches: a list of matches to check for
|
154 |
+
:param default: the value that is returned if none match
|
155 |
+
"""
|
156 |
+
result = default
|
157 |
+
best_quality = -1
|
158 |
+
best_specificity = (-1,)
|
159 |
+
for server_item in matches:
|
160 |
+
match = self._best_single_match(server_item)
|
161 |
+
if not match:
|
162 |
+
continue
|
163 |
+
client_item, quality = match
|
164 |
+
specificity = self._specificity(client_item)
|
165 |
+
if quality <= 0 or quality < best_quality:
|
166 |
+
continue
|
167 |
+
# better quality or same quality but more specific => better match
|
168 |
+
if quality > best_quality or specificity > best_specificity:
|
169 |
+
result = server_item
|
170 |
+
best_quality = quality
|
171 |
+
best_specificity = specificity
|
172 |
+
return result
|
173 |
+
|
174 |
+
@property
|
175 |
+
def best(self):
|
176 |
+
"""The best match as value."""
|
177 |
+
if self:
|
178 |
+
return self[0][0]
|
179 |
+
|
180 |
+
|
181 |
+
_mime_split_re = re.compile(r"/|(?:\s*;\s*)")
|
182 |
+
|
183 |
+
|
184 |
+
def _normalize_mime(value):
|
185 |
+
return _mime_split_re.split(value.lower())
|
186 |
+
|
187 |
+
|
188 |
+
class MIMEAccept(Accept):
|
189 |
+
"""Like :class:`Accept` but with special methods and behavior for
|
190 |
+
mimetypes.
|
191 |
+
"""
|
192 |
+
|
193 |
+
def _specificity(self, value):
|
194 |
+
return tuple(x != "*" for x in _mime_split_re.split(value))
|
195 |
+
|
196 |
+
def _value_matches(self, value, item):
|
197 |
+
# item comes from the client, can't match if it's invalid.
|
198 |
+
if "/" not in item:
|
199 |
+
return False
|
200 |
+
|
201 |
+
# value comes from the application, tell the developer when it
|
202 |
+
# doesn't look valid.
|
203 |
+
if "/" not in value:
|
204 |
+
raise ValueError(f"invalid mimetype {value!r}")
|
205 |
+
|
206 |
+
# Split the match value into type, subtype, and a sorted list of parameters.
|
207 |
+
normalized_value = _normalize_mime(value)
|
208 |
+
value_type, value_subtype = normalized_value[:2]
|
209 |
+
value_params = sorted(normalized_value[2:])
|
210 |
+
|
211 |
+
# "*/*" is the only valid value that can start with "*".
|
212 |
+
if value_type == "*" and value_subtype != "*":
|
213 |
+
raise ValueError(f"invalid mimetype {value!r}")
|
214 |
+
|
215 |
+
# Split the accept item into type, subtype, and parameters.
|
216 |
+
normalized_item = _normalize_mime(item)
|
217 |
+
item_type, item_subtype = normalized_item[:2]
|
218 |
+
item_params = sorted(normalized_item[2:])
|
219 |
+
|
220 |
+
# "*/not-*" from the client is invalid, can't match.
|
221 |
+
if item_type == "*" and item_subtype != "*":
|
222 |
+
return False
|
223 |
+
|
224 |
+
return (
|
225 |
+
(item_type == "*" and item_subtype == "*")
|
226 |
+
or (value_type == "*" and value_subtype == "*")
|
227 |
+
) or (
|
228 |
+
item_type == value_type
|
229 |
+
and (
|
230 |
+
item_subtype == "*"
|
231 |
+
or value_subtype == "*"
|
232 |
+
or (item_subtype == value_subtype and item_params == value_params)
|
233 |
+
)
|
234 |
+
)
|
235 |
+
|
236 |
+
@property
|
237 |
+
def accept_html(self):
|
238 |
+
"""True if this object accepts HTML."""
|
239 |
+
return (
|
240 |
+
"text/html" in self or "application/xhtml+xml" in self or self.accept_xhtml
|
241 |
+
)
|
242 |
+
|
243 |
+
@property
|
244 |
+
def accept_xhtml(self):
|
245 |
+
"""True if this object accepts XHTML."""
|
246 |
+
return "application/xhtml+xml" in self or "application/xml" in self
|
247 |
+
|
248 |
+
@property
|
249 |
+
def accept_json(self):
|
250 |
+
"""True if this object accepts JSON."""
|
251 |
+
return "application/json" in self
|
252 |
+
|
253 |
+
|
254 |
+
_locale_delim_re = re.compile(r"[_-]")
|
255 |
+
|
256 |
+
|
257 |
+
def _normalize_lang(value):
|
258 |
+
"""Process a language tag for matching."""
|
259 |
+
return _locale_delim_re.split(value.lower())
|
260 |
+
|
261 |
+
|
262 |
+
class LanguageAccept(Accept):
|
263 |
+
"""Like :class:`Accept` but with normalization for language tags."""
|
264 |
+
|
265 |
+
def _value_matches(self, value, item):
|
266 |
+
return item == "*" or _normalize_lang(value) == _normalize_lang(item)
|
267 |
+
|
268 |
+
def best_match(self, matches, default=None):
|
269 |
+
"""Given a list of supported values, finds the best match from
|
270 |
+
the list of accepted values.
|
271 |
+
|
272 |
+
Language tags are normalized for the purpose of matching, but
|
273 |
+
are returned unchanged.
|
274 |
+
|
275 |
+
If no exact match is found, this will fall back to matching
|
276 |
+
the first subtag (primary language only), first with the
|
277 |
+
accepted values then with the match values. This partial is not
|
278 |
+
applied to any other language subtags.
|
279 |
+
|
280 |
+
The default is returned if no exact or fallback match is found.
|
281 |
+
|
282 |
+
:param matches: A list of supported languages to find a match.
|
283 |
+
:param default: The value that is returned if none match.
|
284 |
+
"""
|
285 |
+
# Look for an exact match first. If a client accepts "en-US",
|
286 |
+
# "en-US" is a valid match at this point.
|
287 |
+
result = super().best_match(matches)
|
288 |
+
|
289 |
+
if result is not None:
|
290 |
+
return result
|
291 |
+
|
292 |
+
# Fall back to accepting primary tags. If a client accepts
|
293 |
+
# "en-US", "en" is a valid match at this point. Need to use
|
294 |
+
# re.split to account for 2 or 3 letter codes.
|
295 |
+
fallback = Accept(
|
296 |
+
[(_locale_delim_re.split(item[0], 1)[0], item[1]) for item in self]
|
297 |
+
)
|
298 |
+
result = fallback.best_match(matches)
|
299 |
+
|
300 |
+
if result is not None:
|
301 |
+
return result
|
302 |
+
|
303 |
+
# Fall back to matching primary tags. If the client accepts
|
304 |
+
# "en", "en-US" is a valid match at this point.
|
305 |
+
fallback_matches = [_locale_delim_re.split(item, 1)[0] for item in matches]
|
306 |
+
result = super().best_match(fallback_matches)
|
307 |
+
|
308 |
+
# Return a value from the original match list. Find the first
|
309 |
+
# original value that starts with the matched primary tag.
|
310 |
+
if result is not None:
|
311 |
+
return next(item for item in matches if item.startswith(result))
|
312 |
+
|
313 |
+
return default
|
314 |
+
|
315 |
+
|
316 |
+
class CharsetAccept(Accept):
|
317 |
+
"""Like :class:`Accept` but with normalization for charsets."""
|
318 |
+
|
319 |
+
def _value_matches(self, value, item):
|
320 |
+
def _normalize(name):
|
321 |
+
try:
|
322 |
+
return codecs.lookup(name).name
|
323 |
+
except LookupError:
|
324 |
+
return name.lower()
|
325 |
+
|
326 |
+
return item == "*" or _normalize(value) == _normalize(item)
|
MLPY/Lib/site-packages/werkzeug/datastructures/accept.pyi
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections.abc import Iterable
|
2 |
+
from collections.abc import Iterator
|
3 |
+
from typing import overload
|
4 |
+
|
5 |
+
from .structures import ImmutableList
|
6 |
+
|
7 |
+
class Accept(ImmutableList[tuple[str, int]]):
|
8 |
+
provided: bool
|
9 |
+
def __init__(
|
10 |
+
self, values: Accept | Iterable[tuple[str, float]] | None = None
|
11 |
+
) -> None: ...
|
12 |
+
def _specificity(self, value: str) -> tuple[bool, ...]: ...
|
13 |
+
def _value_matches(self, value: str, item: str) -> bool: ...
|
14 |
+
@overload # type: ignore
|
15 |
+
def __getitem__(self, key: str) -> int: ...
|
16 |
+
@overload
|
17 |
+
def __getitem__(self, key: int) -> tuple[str, int]: ...
|
18 |
+
@overload
|
19 |
+
def __getitem__(self, key: slice) -> Iterable[tuple[str, int]]: ...
|
20 |
+
def quality(self, key: str) -> int: ...
|
21 |
+
def __contains__(self, value: str) -> bool: ... # type: ignore
|
22 |
+
def index(self, key: str) -> int: ... # type: ignore
|
23 |
+
def find(self, key: str) -> int: ...
|
24 |
+
def values(self) -> Iterator[str]: ...
|
25 |
+
def to_header(self) -> str: ...
|
26 |
+
def _best_single_match(self, match: str) -> tuple[str, int] | None: ...
|
27 |
+
@overload
|
28 |
+
def best_match(self, matches: Iterable[str], default: str) -> str: ...
|
29 |
+
@overload
|
30 |
+
def best_match(
|
31 |
+
self, matches: Iterable[str], default: str | None = None
|
32 |
+
) -> str | None: ...
|
33 |
+
@property
|
34 |
+
def best(self) -> str: ...
|
35 |
+
|
36 |
+
def _normalize_mime(value: str) -> list[str]: ...
|
37 |
+
|
38 |
+
class MIMEAccept(Accept):
|
39 |
+
def _specificity(self, value: str) -> tuple[bool, ...]: ...
|
40 |
+
def _value_matches(self, value: str, item: str) -> bool: ...
|
41 |
+
@property
|
42 |
+
def accept_html(self) -> bool: ...
|
43 |
+
@property
|
44 |
+
def accept_xhtml(self) -> bool: ...
|
45 |
+
@property
|
46 |
+
def accept_json(self) -> bool: ...
|
47 |
+
|
48 |
+
def _normalize_lang(value: str) -> list[str]: ...
|
49 |
+
|
50 |
+
class LanguageAccept(Accept):
|
51 |
+
def _value_matches(self, value: str, item: str) -> bool: ...
|
52 |
+
|
53 |
+
class CharsetAccept(Accept):
|
54 |
+
def _value_matches(self, value: str, item: str) -> bool: ...
|
MLPY/Lib/site-packages/werkzeug/datastructures/auth.py
ADDED
@@ -0,0 +1,316 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import base64
|
4 |
+
import binascii
|
5 |
+
import typing as t
|
6 |
+
|
7 |
+
from ..http import dump_header
|
8 |
+
from ..http import parse_dict_header
|
9 |
+
from ..http import quote_header_value
|
10 |
+
from .structures import CallbackDict
|
11 |
+
|
12 |
+
if t.TYPE_CHECKING:
|
13 |
+
import typing_extensions as te
|
14 |
+
|
15 |
+
|
16 |
+
class Authorization:
|
17 |
+
"""Represents the parts of an ``Authorization`` request header.
|
18 |
+
|
19 |
+
:attr:`.Request.authorization` returns an instance if the header is set.
|
20 |
+
|
21 |
+
An instance can be used with the test :class:`.Client` request methods' ``auth``
|
22 |
+
parameter to send the header in test requests.
|
23 |
+
|
24 |
+
Depending on the auth scheme, either :attr:`parameters` or :attr:`token` will be
|
25 |
+
set. The ``Basic`` scheme's token is decoded into the ``username`` and ``password``
|
26 |
+
parameters.
|
27 |
+
|
28 |
+
For convenience, ``auth["key"]`` and ``auth.key`` both access the key in the
|
29 |
+
:attr:`parameters` dict, along with ``auth.get("key")`` and ``"key" in auth``.
|
30 |
+
|
31 |
+
.. versionchanged:: 2.3
|
32 |
+
The ``token`` parameter and attribute was added to support auth schemes that use
|
33 |
+
a token instead of parameters, such as ``Bearer``.
|
34 |
+
|
35 |
+
.. versionchanged:: 2.3
|
36 |
+
The object is no longer a ``dict``.
|
37 |
+
|
38 |
+
.. versionchanged:: 0.5
|
39 |
+
The object is an immutable dict.
|
40 |
+
"""
|
41 |
+
|
42 |
+
def __init__(
|
43 |
+
self,
|
44 |
+
auth_type: str,
|
45 |
+
data: dict[str, str | None] | None = None,
|
46 |
+
token: str | None = None,
|
47 |
+
) -> None:
|
48 |
+
self.type = auth_type
|
49 |
+
"""The authorization scheme, like ``basic``, ``digest``, or ``bearer``."""
|
50 |
+
|
51 |
+
if data is None:
|
52 |
+
data = {}
|
53 |
+
|
54 |
+
self.parameters = data
|
55 |
+
"""A dict of parameters parsed from the header. Either this or :attr:`token`
|
56 |
+
will have a value for a given scheme.
|
57 |
+
"""
|
58 |
+
|
59 |
+
self.token = token
|
60 |
+
"""A token parsed from the header. Either this or :attr:`parameters` will have a
|
61 |
+
value for a given scheme.
|
62 |
+
|
63 |
+
.. versionadded:: 2.3
|
64 |
+
"""
|
65 |
+
|
66 |
+
def __getattr__(self, name: str) -> str | None:
|
67 |
+
return self.parameters.get(name)
|
68 |
+
|
69 |
+
def __getitem__(self, name: str) -> str | None:
|
70 |
+
return self.parameters.get(name)
|
71 |
+
|
72 |
+
def get(self, key: str, default: str | None = None) -> str | None:
|
73 |
+
return self.parameters.get(key, default)
|
74 |
+
|
75 |
+
def __contains__(self, key: str) -> bool:
|
76 |
+
return key in self.parameters
|
77 |
+
|
78 |
+
def __eq__(self, other: object) -> bool:
|
79 |
+
if not isinstance(other, Authorization):
|
80 |
+
return NotImplemented
|
81 |
+
|
82 |
+
return (
|
83 |
+
other.type == self.type
|
84 |
+
and other.token == self.token
|
85 |
+
and other.parameters == self.parameters
|
86 |
+
)
|
87 |
+
|
88 |
+
@classmethod
|
89 |
+
def from_header(cls, value: str | None) -> te.Self | None:
|
90 |
+
"""Parse an ``Authorization`` header value and return an instance, or ``None``
|
91 |
+
if the value is empty.
|
92 |
+
|
93 |
+
:param value: The header value to parse.
|
94 |
+
|
95 |
+
.. versionadded:: 2.3
|
96 |
+
"""
|
97 |
+
if not value:
|
98 |
+
return None
|
99 |
+
|
100 |
+
scheme, _, rest = value.partition(" ")
|
101 |
+
scheme = scheme.lower()
|
102 |
+
rest = rest.strip()
|
103 |
+
|
104 |
+
if scheme == "basic":
|
105 |
+
try:
|
106 |
+
username, _, password = base64.b64decode(rest).decode().partition(":")
|
107 |
+
except (binascii.Error, UnicodeError):
|
108 |
+
return None
|
109 |
+
|
110 |
+
return cls(scheme, {"username": username, "password": password})
|
111 |
+
|
112 |
+
if "=" in rest.rstrip("="):
|
113 |
+
# = that is not trailing, this is parameters.
|
114 |
+
return cls(scheme, parse_dict_header(rest), None)
|
115 |
+
|
116 |
+
# No = or only trailing =, this is a token.
|
117 |
+
return cls(scheme, None, rest)
|
118 |
+
|
119 |
+
def to_header(self) -> str:
|
120 |
+
"""Produce an ``Authorization`` header value representing this data.
|
121 |
+
|
122 |
+
.. versionadded:: 2.0
|
123 |
+
"""
|
124 |
+
if self.type == "basic":
|
125 |
+
value = base64.b64encode(
|
126 |
+
f"{self.username}:{self.password}".encode()
|
127 |
+
).decode("ascii")
|
128 |
+
return f"Basic {value}"
|
129 |
+
|
130 |
+
if self.token is not None:
|
131 |
+
return f"{self.type.title()} {self.token}"
|
132 |
+
|
133 |
+
return f"{self.type.title()} {dump_header(self.parameters)}"
|
134 |
+
|
135 |
+
def __str__(self) -> str:
|
136 |
+
return self.to_header()
|
137 |
+
|
138 |
+
def __repr__(self) -> str:
|
139 |
+
return f"<{type(self).__name__} {self.to_header()}>"
|
140 |
+
|
141 |
+
|
142 |
+
class WWWAuthenticate:
|
143 |
+
"""Represents the parts of a ``WWW-Authenticate`` response header.
|
144 |
+
|
145 |
+
Set :attr:`.Response.www_authenticate` to an instance of list of instances to set
|
146 |
+
values for this header in the response. Modifying this instance will modify the
|
147 |
+
header value.
|
148 |
+
|
149 |
+
Depending on the auth scheme, either :attr:`parameters` or :attr:`token` should be
|
150 |
+
set. The ``Basic`` scheme will encode ``username`` and ``password`` parameters to a
|
151 |
+
token.
|
152 |
+
|
153 |
+
For convenience, ``auth["key"]`` and ``auth.key`` both act on the :attr:`parameters`
|
154 |
+
dict, and can be used to get, set, or delete parameters. ``auth.get("key")`` and
|
155 |
+
``"key" in auth`` are also provided.
|
156 |
+
|
157 |
+
.. versionchanged:: 2.3
|
158 |
+
The ``token`` parameter and attribute was added to support auth schemes that use
|
159 |
+
a token instead of parameters, such as ``Bearer``.
|
160 |
+
|
161 |
+
.. versionchanged:: 2.3
|
162 |
+
The object is no longer a ``dict``.
|
163 |
+
|
164 |
+
.. versionchanged:: 2.3
|
165 |
+
The ``on_update`` parameter was removed.
|
166 |
+
"""
|
167 |
+
|
168 |
+
def __init__(
|
169 |
+
self,
|
170 |
+
auth_type: str,
|
171 |
+
values: dict[str, str | None] | None = None,
|
172 |
+
token: str | None = None,
|
173 |
+
):
|
174 |
+
self._type = auth_type.lower()
|
175 |
+
self._parameters: dict[str, str | None] = CallbackDict(
|
176 |
+
values, lambda _: self._trigger_on_update()
|
177 |
+
)
|
178 |
+
self._token = token
|
179 |
+
self._on_update: t.Callable[[WWWAuthenticate], None] | None = None
|
180 |
+
|
181 |
+
def _trigger_on_update(self) -> None:
|
182 |
+
if self._on_update is not None:
|
183 |
+
self._on_update(self)
|
184 |
+
|
185 |
+
@property
|
186 |
+
def type(self) -> str:
|
187 |
+
"""The authorization scheme, like ``basic``, ``digest``, or ``bearer``."""
|
188 |
+
return self._type
|
189 |
+
|
190 |
+
@type.setter
|
191 |
+
def type(self, value: str) -> None:
|
192 |
+
self._type = value
|
193 |
+
self._trigger_on_update()
|
194 |
+
|
195 |
+
@property
|
196 |
+
def parameters(self) -> dict[str, str | None]:
|
197 |
+
"""A dict of parameters for the header. Only one of this or :attr:`token` should
|
198 |
+
have a value for a given scheme.
|
199 |
+
"""
|
200 |
+
return self._parameters
|
201 |
+
|
202 |
+
@parameters.setter
|
203 |
+
def parameters(self, value: dict[str, str]) -> None:
|
204 |
+
self._parameters = CallbackDict(value, lambda _: self._trigger_on_update())
|
205 |
+
self._trigger_on_update()
|
206 |
+
|
207 |
+
@property
|
208 |
+
def token(self) -> str | None:
|
209 |
+
"""A dict of parameters for the header. Only one of this or :attr:`token` should
|
210 |
+
have a value for a given scheme.
|
211 |
+
"""
|
212 |
+
return self._token
|
213 |
+
|
214 |
+
@token.setter
|
215 |
+
def token(self, value: str | None) -> None:
|
216 |
+
"""A token for the header. Only one of this or :attr:`parameters` should have a
|
217 |
+
value for a given scheme.
|
218 |
+
|
219 |
+
.. versionadded:: 2.3
|
220 |
+
"""
|
221 |
+
self._token = value
|
222 |
+
self._trigger_on_update()
|
223 |
+
|
224 |
+
def __getitem__(self, key: str) -> str | None:
|
225 |
+
return self.parameters.get(key)
|
226 |
+
|
227 |
+
def __setitem__(self, key: str, value: str | None) -> None:
|
228 |
+
if value is None:
|
229 |
+
if key in self.parameters:
|
230 |
+
del self.parameters[key]
|
231 |
+
else:
|
232 |
+
self.parameters[key] = value
|
233 |
+
|
234 |
+
self._trigger_on_update()
|
235 |
+
|
236 |
+
def __delitem__(self, key: str) -> None:
|
237 |
+
if key in self.parameters:
|
238 |
+
del self.parameters[key]
|
239 |
+
self._trigger_on_update()
|
240 |
+
|
241 |
+
def __getattr__(self, name: str) -> str | None:
|
242 |
+
return self[name]
|
243 |
+
|
244 |
+
def __setattr__(self, name: str, value: str | None) -> None:
|
245 |
+
if name in {"_type", "_parameters", "_token", "_on_update"}:
|
246 |
+
super().__setattr__(name, value)
|
247 |
+
else:
|
248 |
+
self[name] = value
|
249 |
+
|
250 |
+
def __delattr__(self, name: str) -> None:
|
251 |
+
del self[name]
|
252 |
+
|
253 |
+
def __contains__(self, key: str) -> bool:
|
254 |
+
return key in self.parameters
|
255 |
+
|
256 |
+
def __eq__(self, other: object) -> bool:
|
257 |
+
if not isinstance(other, WWWAuthenticate):
|
258 |
+
return NotImplemented
|
259 |
+
|
260 |
+
return (
|
261 |
+
other.type == self.type
|
262 |
+
and other.token == self.token
|
263 |
+
and other.parameters == self.parameters
|
264 |
+
)
|
265 |
+
|
266 |
+
def get(self, key: str, default: str | None = None) -> str | None:
|
267 |
+
return self.parameters.get(key, default)
|
268 |
+
|
269 |
+
@classmethod
|
270 |
+
def from_header(cls, value: str | None) -> te.Self | None:
|
271 |
+
"""Parse a ``WWW-Authenticate`` header value and return an instance, or ``None``
|
272 |
+
if the value is empty.
|
273 |
+
|
274 |
+
:param value: The header value to parse.
|
275 |
+
|
276 |
+
.. versionadded:: 2.3
|
277 |
+
"""
|
278 |
+
if not value:
|
279 |
+
return None
|
280 |
+
|
281 |
+
scheme, _, rest = value.partition(" ")
|
282 |
+
scheme = scheme.lower()
|
283 |
+
rest = rest.strip()
|
284 |
+
|
285 |
+
if "=" in rest.rstrip("="):
|
286 |
+
# = that is not trailing, this is parameters.
|
287 |
+
return cls(scheme, parse_dict_header(rest), None)
|
288 |
+
|
289 |
+
# No = or only trailing =, this is a token.
|
290 |
+
return cls(scheme, None, rest)
|
291 |
+
|
292 |
+
def to_header(self) -> str:
|
293 |
+
"""Produce a ``WWW-Authenticate`` header value representing this data."""
|
294 |
+
if self.token is not None:
|
295 |
+
return f"{self.type.title()} {self.token}"
|
296 |
+
|
297 |
+
if self.type == "digest":
|
298 |
+
items = []
|
299 |
+
|
300 |
+
for key, value in self.parameters.items():
|
301 |
+
if key in {"realm", "domain", "nonce", "opaque", "qop"}:
|
302 |
+
value = quote_header_value(value, allow_token=False)
|
303 |
+
else:
|
304 |
+
value = quote_header_value(value)
|
305 |
+
|
306 |
+
items.append(f"{key}={value}")
|
307 |
+
|
308 |
+
return f"Digest {', '.join(items)}"
|
309 |
+
|
310 |
+
return f"{self.type.title()} {dump_header(self.parameters)}"
|
311 |
+
|
312 |
+
def __str__(self) -> str:
|
313 |
+
return self.to_header()
|
314 |
+
|
315 |
+
def __repr__(self) -> str:
|
316 |
+
return f"<{type(self).__name__} {self.to_header()}>"
|
MLPY/Lib/site-packages/werkzeug/datastructures/cache_control.py
ADDED
@@ -0,0 +1,175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from .mixins import ImmutableDictMixin
|
4 |
+
from .mixins import UpdateDictMixin
|
5 |
+
|
6 |
+
|
7 |
+
def cache_control_property(key, empty, type):
|
8 |
+
"""Return a new property object for a cache header. Useful if you
|
9 |
+
want to add support for a cache extension in a subclass.
|
10 |
+
|
11 |
+
.. versionchanged:: 2.0
|
12 |
+
Renamed from ``cache_property``.
|
13 |
+
"""
|
14 |
+
return property(
|
15 |
+
lambda x: x._get_cache_value(key, empty, type),
|
16 |
+
lambda x, v: x._set_cache_value(key, v, type),
|
17 |
+
lambda x: x._del_cache_value(key),
|
18 |
+
f"accessor for {key!r}",
|
19 |
+
)
|
20 |
+
|
21 |
+
|
22 |
+
class _CacheControl(UpdateDictMixin, dict):
|
23 |
+
"""Subclass of a dict that stores values for a Cache-Control header. It
|
24 |
+
has accessors for all the cache-control directives specified in RFC 2616.
|
25 |
+
The class does not differentiate between request and response directives.
|
26 |
+
|
27 |
+
Because the cache-control directives in the HTTP header use dashes the
|
28 |
+
python descriptors use underscores for that.
|
29 |
+
|
30 |
+
To get a header of the :class:`CacheControl` object again you can convert
|
31 |
+
the object into a string or call the :meth:`to_header` method. If you plan
|
32 |
+
to subclass it and add your own items have a look at the sourcecode for
|
33 |
+
that class.
|
34 |
+
|
35 |
+
.. versionchanged:: 2.1.0
|
36 |
+
Setting int properties such as ``max_age`` will convert the
|
37 |
+
value to an int.
|
38 |
+
|
39 |
+
.. versionchanged:: 0.4
|
40 |
+
|
41 |
+
Setting `no_cache` or `private` to boolean `True` will set the implicit
|
42 |
+
none-value which is ``*``:
|
43 |
+
|
44 |
+
>>> cc = ResponseCacheControl()
|
45 |
+
>>> cc.no_cache = True
|
46 |
+
>>> cc
|
47 |
+
<ResponseCacheControl 'no-cache'>
|
48 |
+
>>> cc.no_cache
|
49 |
+
'*'
|
50 |
+
>>> cc.no_cache = None
|
51 |
+
>>> cc
|
52 |
+
<ResponseCacheControl ''>
|
53 |
+
|
54 |
+
In versions before 0.5 the behavior documented here affected the now
|
55 |
+
no longer existing `CacheControl` class.
|
56 |
+
"""
|
57 |
+
|
58 |
+
no_cache = cache_control_property("no-cache", "*", None)
|
59 |
+
no_store = cache_control_property("no-store", None, bool)
|
60 |
+
max_age = cache_control_property("max-age", -1, int)
|
61 |
+
no_transform = cache_control_property("no-transform", None, None)
|
62 |
+
|
63 |
+
def __init__(self, values=(), on_update=None):
|
64 |
+
dict.__init__(self, values or ())
|
65 |
+
self.on_update = on_update
|
66 |
+
self.provided = values is not None
|
67 |
+
|
68 |
+
def _get_cache_value(self, key, empty, type):
|
69 |
+
"""Used internally by the accessor properties."""
|
70 |
+
if type is bool:
|
71 |
+
return key in self
|
72 |
+
if key in self:
|
73 |
+
value = self[key]
|
74 |
+
if value is None:
|
75 |
+
return empty
|
76 |
+
elif type is not None:
|
77 |
+
try:
|
78 |
+
value = type(value)
|
79 |
+
except ValueError:
|
80 |
+
pass
|
81 |
+
return value
|
82 |
+
return None
|
83 |
+
|
84 |
+
def _set_cache_value(self, key, value, type):
|
85 |
+
"""Used internally by the accessor properties."""
|
86 |
+
if type is bool:
|
87 |
+
if value:
|
88 |
+
self[key] = None
|
89 |
+
else:
|
90 |
+
self.pop(key, None)
|
91 |
+
else:
|
92 |
+
if value is None:
|
93 |
+
self.pop(key, None)
|
94 |
+
elif value is True:
|
95 |
+
self[key] = None
|
96 |
+
else:
|
97 |
+
if type is not None:
|
98 |
+
self[key] = type(value)
|
99 |
+
else:
|
100 |
+
self[key] = value
|
101 |
+
|
102 |
+
def _del_cache_value(self, key):
|
103 |
+
"""Used internally by the accessor properties."""
|
104 |
+
if key in self:
|
105 |
+
del self[key]
|
106 |
+
|
107 |
+
def to_header(self):
|
108 |
+
"""Convert the stored values into a cache control header."""
|
109 |
+
return http.dump_header(self)
|
110 |
+
|
111 |
+
def __str__(self):
|
112 |
+
return self.to_header()
|
113 |
+
|
114 |
+
def __repr__(self):
|
115 |
+
kv_str = " ".join(f"{k}={v!r}" for k, v in sorted(self.items()))
|
116 |
+
return f"<{type(self).__name__} {kv_str}>"
|
117 |
+
|
118 |
+
cache_property = staticmethod(cache_control_property)
|
119 |
+
|
120 |
+
|
121 |
+
class RequestCacheControl(ImmutableDictMixin, _CacheControl):
|
122 |
+
"""A cache control for requests. This is immutable and gives access
|
123 |
+
to all the request-relevant cache control headers.
|
124 |
+
|
125 |
+
To get a header of the :class:`RequestCacheControl` object again you can
|
126 |
+
convert the object into a string or call the :meth:`to_header` method. If
|
127 |
+
you plan to subclass it and add your own items have a look at the sourcecode
|
128 |
+
for that class.
|
129 |
+
|
130 |
+
.. versionchanged:: 2.1.0
|
131 |
+
Setting int properties such as ``max_age`` will convert the
|
132 |
+
value to an int.
|
133 |
+
|
134 |
+
.. versionadded:: 0.5
|
135 |
+
In previous versions a `CacheControl` class existed that was used
|
136 |
+
both for request and response.
|
137 |
+
"""
|
138 |
+
|
139 |
+
max_stale = cache_control_property("max-stale", "*", int)
|
140 |
+
min_fresh = cache_control_property("min-fresh", "*", int)
|
141 |
+
only_if_cached = cache_control_property("only-if-cached", None, bool)
|
142 |
+
|
143 |
+
|
144 |
+
class ResponseCacheControl(_CacheControl):
|
145 |
+
"""A cache control for responses. Unlike :class:`RequestCacheControl`
|
146 |
+
this is mutable and gives access to response-relevant cache control
|
147 |
+
headers.
|
148 |
+
|
149 |
+
To get a header of the :class:`ResponseCacheControl` object again you can
|
150 |
+
convert the object into a string or call the :meth:`to_header` method. If
|
151 |
+
you plan to subclass it and add your own items have a look at the sourcecode
|
152 |
+
for that class.
|
153 |
+
|
154 |
+
.. versionchanged:: 2.1.1
|
155 |
+
``s_maxage`` converts the value to an int.
|
156 |
+
|
157 |
+
.. versionchanged:: 2.1.0
|
158 |
+
Setting int properties such as ``max_age`` will convert the
|
159 |
+
value to an int.
|
160 |
+
|
161 |
+
.. versionadded:: 0.5
|
162 |
+
In previous versions a `CacheControl` class existed that was used
|
163 |
+
both for request and response.
|
164 |
+
"""
|
165 |
+
|
166 |
+
public = cache_control_property("public", None, bool)
|
167 |
+
private = cache_control_property("private", "*", None)
|
168 |
+
must_revalidate = cache_control_property("must-revalidate", None, bool)
|
169 |
+
proxy_revalidate = cache_control_property("proxy-revalidate", None, bool)
|
170 |
+
s_maxage = cache_control_property("s-maxage", None, int)
|
171 |
+
immutable = cache_control_property("immutable", None, bool)
|
172 |
+
|
173 |
+
|
174 |
+
# circular dependencies
|
175 |
+
from .. import http
|
MLPY/Lib/site-packages/werkzeug/datastructures/cache_control.pyi
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections.abc import Callable
|
2 |
+
from collections.abc import Iterable
|
3 |
+
from collections.abc import Mapping
|
4 |
+
from typing import TypeVar
|
5 |
+
|
6 |
+
from .mixins import ImmutableDictMixin
|
7 |
+
from .mixins import UpdateDictMixin
|
8 |
+
|
9 |
+
T = TypeVar("T")
|
10 |
+
_CPT = TypeVar("_CPT", str, int, bool)
|
11 |
+
|
12 |
+
def cache_control_property(
|
13 |
+
key: str, empty: _CPT | None, type: type[_CPT]
|
14 |
+
) -> property: ...
|
15 |
+
|
16 |
+
class _CacheControl(
|
17 |
+
UpdateDictMixin[str, str | int | bool | None], dict[str, str | int | bool | None]
|
18 |
+
):
|
19 |
+
provided: bool
|
20 |
+
def __init__(
|
21 |
+
self,
|
22 |
+
values: Mapping[str, str | int | bool | None]
|
23 |
+
| Iterable[tuple[str, str | int | bool | None]] = (),
|
24 |
+
on_update: Callable[[_CacheControl], None] | None = None,
|
25 |
+
) -> None: ...
|
26 |
+
@property
|
27 |
+
def no_cache(self) -> bool | None: ...
|
28 |
+
@no_cache.setter
|
29 |
+
def no_cache(self, value: bool | None) -> None: ...
|
30 |
+
@no_cache.deleter
|
31 |
+
def no_cache(self) -> None: ...
|
32 |
+
@property
|
33 |
+
def no_store(self) -> bool | None: ...
|
34 |
+
@no_store.setter
|
35 |
+
def no_store(self, value: bool | None) -> None: ...
|
36 |
+
@no_store.deleter
|
37 |
+
def no_store(self) -> None: ...
|
38 |
+
@property
|
39 |
+
def max_age(self) -> int | None: ...
|
40 |
+
@max_age.setter
|
41 |
+
def max_age(self, value: int | None) -> None: ...
|
42 |
+
@max_age.deleter
|
43 |
+
def max_age(self) -> None: ...
|
44 |
+
@property
|
45 |
+
def no_transform(self) -> bool | None: ...
|
46 |
+
@no_transform.setter
|
47 |
+
def no_transform(self, value: bool | None) -> None: ...
|
48 |
+
@no_transform.deleter
|
49 |
+
def no_transform(self) -> None: ...
|
50 |
+
def _get_cache_value(self, key: str, empty: T | None, type: type[T]) -> T: ...
|
51 |
+
def _set_cache_value(self, key: str, value: T | None, type: type[T]) -> None: ...
|
52 |
+
def _del_cache_value(self, key: str) -> None: ...
|
53 |
+
def to_header(self) -> str: ...
|
54 |
+
@staticmethod
|
55 |
+
def cache_property(key: str, empty: _CPT | None, type: type[_CPT]) -> property: ...
|
56 |
+
|
57 |
+
class RequestCacheControl( # type: ignore[misc]
|
58 |
+
ImmutableDictMixin[str, str | int | bool | None], _CacheControl
|
59 |
+
):
|
60 |
+
@property
|
61 |
+
def max_stale(self) -> int | None: ...
|
62 |
+
@max_stale.setter
|
63 |
+
def max_stale(self, value: int | None) -> None: ...
|
64 |
+
@max_stale.deleter
|
65 |
+
def max_stale(self) -> None: ...
|
66 |
+
@property
|
67 |
+
def min_fresh(self) -> int | None: ...
|
68 |
+
@min_fresh.setter
|
69 |
+
def min_fresh(self, value: int | None) -> None: ...
|
70 |
+
@min_fresh.deleter
|
71 |
+
def min_fresh(self) -> None: ...
|
72 |
+
@property
|
73 |
+
def only_if_cached(self) -> bool | None: ...
|
74 |
+
@only_if_cached.setter
|
75 |
+
def only_if_cached(self, value: bool | None) -> None: ...
|
76 |
+
@only_if_cached.deleter
|
77 |
+
def only_if_cached(self) -> None: ...
|
78 |
+
|
79 |
+
class ResponseCacheControl(_CacheControl):
|
80 |
+
@property
|
81 |
+
def public(self) -> bool | None: ...
|
82 |
+
@public.setter
|
83 |
+
def public(self, value: bool | None) -> None: ...
|
84 |
+
@public.deleter
|
85 |
+
def public(self) -> None: ...
|
86 |
+
@property
|
87 |
+
def private(self) -> bool | None: ...
|
88 |
+
@private.setter
|
89 |
+
def private(self, value: bool | None) -> None: ...
|
90 |
+
@private.deleter
|
91 |
+
def private(self) -> None: ...
|
92 |
+
@property
|
93 |
+
def must_revalidate(self) -> bool | None: ...
|
94 |
+
@must_revalidate.setter
|
95 |
+
def must_revalidate(self, value: bool | None) -> None: ...
|
96 |
+
@must_revalidate.deleter
|
97 |
+
def must_revalidate(self) -> None: ...
|
98 |
+
@property
|
99 |
+
def proxy_revalidate(self) -> bool | None: ...
|
100 |
+
@proxy_revalidate.setter
|
101 |
+
def proxy_revalidate(self, value: bool | None) -> None: ...
|
102 |
+
@proxy_revalidate.deleter
|
103 |
+
def proxy_revalidate(self) -> None: ...
|
104 |
+
@property
|
105 |
+
def s_maxage(self) -> int | None: ...
|
106 |
+
@s_maxage.setter
|
107 |
+
def s_maxage(self, value: int | None) -> None: ...
|
108 |
+
@s_maxage.deleter
|
109 |
+
def s_maxage(self) -> None: ...
|
110 |
+
@property
|
111 |
+
def immutable(self) -> bool | None: ...
|
112 |
+
@immutable.setter
|
113 |
+
def immutable(self, value: bool | None) -> None: ...
|
114 |
+
@immutable.deleter
|
115 |
+
def immutable(self) -> None: ...
|
MLPY/Lib/site-packages/werkzeug/datastructures/csp.py
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from .mixins import UpdateDictMixin
|
4 |
+
|
5 |
+
|
6 |
+
def csp_property(key):
|
7 |
+
"""Return a new property object for a content security policy header.
|
8 |
+
Useful if you want to add support for a csp extension in a
|
9 |
+
subclass.
|
10 |
+
"""
|
11 |
+
return property(
|
12 |
+
lambda x: x._get_value(key),
|
13 |
+
lambda x, v: x._set_value(key, v),
|
14 |
+
lambda x: x._del_value(key),
|
15 |
+
f"accessor for {key!r}",
|
16 |
+
)
|
17 |
+
|
18 |
+
|
19 |
+
class ContentSecurityPolicy(UpdateDictMixin, dict):
|
20 |
+
"""Subclass of a dict that stores values for a Content Security Policy
|
21 |
+
header. It has accessors for all the level 3 policies.
|
22 |
+
|
23 |
+
Because the csp directives in the HTTP header use dashes the
|
24 |
+
python descriptors use underscores for that.
|
25 |
+
|
26 |
+
To get a header of the :class:`ContentSecuirtyPolicy` object again
|
27 |
+
you can convert the object into a string or call the
|
28 |
+
:meth:`to_header` method. If you plan to subclass it and add your
|
29 |
+
own items have a look at the sourcecode for that class.
|
30 |
+
|
31 |
+
.. versionadded:: 1.0.0
|
32 |
+
Support for Content Security Policy headers was added.
|
33 |
+
|
34 |
+
"""
|
35 |
+
|
36 |
+
base_uri = csp_property("base-uri")
|
37 |
+
child_src = csp_property("child-src")
|
38 |
+
connect_src = csp_property("connect-src")
|
39 |
+
default_src = csp_property("default-src")
|
40 |
+
font_src = csp_property("font-src")
|
41 |
+
form_action = csp_property("form-action")
|
42 |
+
frame_ancestors = csp_property("frame-ancestors")
|
43 |
+
frame_src = csp_property("frame-src")
|
44 |
+
img_src = csp_property("img-src")
|
45 |
+
manifest_src = csp_property("manifest-src")
|
46 |
+
media_src = csp_property("media-src")
|
47 |
+
navigate_to = csp_property("navigate-to")
|
48 |
+
object_src = csp_property("object-src")
|
49 |
+
prefetch_src = csp_property("prefetch-src")
|
50 |
+
plugin_types = csp_property("plugin-types")
|
51 |
+
report_to = csp_property("report-to")
|
52 |
+
report_uri = csp_property("report-uri")
|
53 |
+
sandbox = csp_property("sandbox")
|
54 |
+
script_src = csp_property("script-src")
|
55 |
+
script_src_attr = csp_property("script-src-attr")
|
56 |
+
script_src_elem = csp_property("script-src-elem")
|
57 |
+
style_src = csp_property("style-src")
|
58 |
+
style_src_attr = csp_property("style-src-attr")
|
59 |
+
style_src_elem = csp_property("style-src-elem")
|
60 |
+
worker_src = csp_property("worker-src")
|
61 |
+
|
62 |
+
def __init__(self, values=(), on_update=None):
|
63 |
+
dict.__init__(self, values or ())
|
64 |
+
self.on_update = on_update
|
65 |
+
self.provided = values is not None
|
66 |
+
|
67 |
+
def _get_value(self, key):
|
68 |
+
"""Used internally by the accessor properties."""
|
69 |
+
return self.get(key)
|
70 |
+
|
71 |
+
def _set_value(self, key, value):
|
72 |
+
"""Used internally by the accessor properties."""
|
73 |
+
if value is None:
|
74 |
+
self.pop(key, None)
|
75 |
+
else:
|
76 |
+
self[key] = value
|
77 |
+
|
78 |
+
def _del_value(self, key):
|
79 |
+
"""Used internally by the accessor properties."""
|
80 |
+
if key in self:
|
81 |
+
del self[key]
|
82 |
+
|
83 |
+
def to_header(self):
|
84 |
+
"""Convert the stored values into a cache control header."""
|
85 |
+
from ..http import dump_csp_header
|
86 |
+
|
87 |
+
return dump_csp_header(self)
|
88 |
+
|
89 |
+
def __str__(self):
|
90 |
+
return self.to_header()
|
91 |
+
|
92 |
+
def __repr__(self):
|
93 |
+
kv_str = " ".join(f"{k}={v!r}" for k, v in sorted(self.items()))
|
94 |
+
return f"<{type(self).__name__} {kv_str}>"
|
MLPY/Lib/site-packages/werkzeug/datastructures/csp.pyi
ADDED
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections.abc import Callable
|
2 |
+
from collections.abc import Iterable
|
3 |
+
from collections.abc import Mapping
|
4 |
+
|
5 |
+
from .mixins import UpdateDictMixin
|
6 |
+
|
7 |
+
def csp_property(key: str) -> property: ...
|
8 |
+
|
9 |
+
class ContentSecurityPolicy(UpdateDictMixin[str, str], dict[str, str]):
|
10 |
+
@property
|
11 |
+
def base_uri(self) -> str | None: ...
|
12 |
+
@base_uri.setter
|
13 |
+
def base_uri(self, value: str | None) -> None: ...
|
14 |
+
@base_uri.deleter
|
15 |
+
def base_uri(self) -> None: ...
|
16 |
+
@property
|
17 |
+
def child_src(self) -> str | None: ...
|
18 |
+
@child_src.setter
|
19 |
+
def child_src(self, value: str | None) -> None: ...
|
20 |
+
@child_src.deleter
|
21 |
+
def child_src(self) -> None: ...
|
22 |
+
@property
|
23 |
+
def connect_src(self) -> str | None: ...
|
24 |
+
@connect_src.setter
|
25 |
+
def connect_src(self, value: str | None) -> None: ...
|
26 |
+
@connect_src.deleter
|
27 |
+
def connect_src(self) -> None: ...
|
28 |
+
@property
|
29 |
+
def default_src(self) -> str | None: ...
|
30 |
+
@default_src.setter
|
31 |
+
def default_src(self, value: str | None) -> None: ...
|
32 |
+
@default_src.deleter
|
33 |
+
def default_src(self) -> None: ...
|
34 |
+
@property
|
35 |
+
def font_src(self) -> str | None: ...
|
36 |
+
@font_src.setter
|
37 |
+
def font_src(self, value: str | None) -> None: ...
|
38 |
+
@font_src.deleter
|
39 |
+
def font_src(self) -> None: ...
|
40 |
+
@property
|
41 |
+
def form_action(self) -> str | None: ...
|
42 |
+
@form_action.setter
|
43 |
+
def form_action(self, value: str | None) -> None: ...
|
44 |
+
@form_action.deleter
|
45 |
+
def form_action(self) -> None: ...
|
46 |
+
@property
|
47 |
+
def frame_ancestors(self) -> str | None: ...
|
48 |
+
@frame_ancestors.setter
|
49 |
+
def frame_ancestors(self, value: str | None) -> None: ...
|
50 |
+
@frame_ancestors.deleter
|
51 |
+
def frame_ancestors(self) -> None: ...
|
52 |
+
@property
|
53 |
+
def frame_src(self) -> str | None: ...
|
54 |
+
@frame_src.setter
|
55 |
+
def frame_src(self, value: str | None) -> None: ...
|
56 |
+
@frame_src.deleter
|
57 |
+
def frame_src(self) -> None: ...
|
58 |
+
@property
|
59 |
+
def img_src(self) -> str | None: ...
|
60 |
+
@img_src.setter
|
61 |
+
def img_src(self, value: str | None) -> None: ...
|
62 |
+
@img_src.deleter
|
63 |
+
def img_src(self) -> None: ...
|
64 |
+
@property
|
65 |
+
def manifest_src(self) -> str | None: ...
|
66 |
+
@manifest_src.setter
|
67 |
+
def manifest_src(self, value: str | None) -> None: ...
|
68 |
+
@manifest_src.deleter
|
69 |
+
def manifest_src(self) -> None: ...
|
70 |
+
@property
|
71 |
+
def media_src(self) -> str | None: ...
|
72 |
+
@media_src.setter
|
73 |
+
def media_src(self, value: str | None) -> None: ...
|
74 |
+
@media_src.deleter
|
75 |
+
def media_src(self) -> None: ...
|
76 |
+
@property
|
77 |
+
def navigate_to(self) -> str | None: ...
|
78 |
+
@navigate_to.setter
|
79 |
+
def navigate_to(self, value: str | None) -> None: ...
|
80 |
+
@navigate_to.deleter
|
81 |
+
def navigate_to(self) -> None: ...
|
82 |
+
@property
|
83 |
+
def object_src(self) -> str | None: ...
|
84 |
+
@object_src.setter
|
85 |
+
def object_src(self, value: str | None) -> None: ...
|
86 |
+
@object_src.deleter
|
87 |
+
def object_src(self) -> None: ...
|
88 |
+
@property
|
89 |
+
def prefetch_src(self) -> str | None: ...
|
90 |
+
@prefetch_src.setter
|
91 |
+
def prefetch_src(self, value: str | None) -> None: ...
|
92 |
+
@prefetch_src.deleter
|
93 |
+
def prefetch_src(self) -> None: ...
|
94 |
+
@property
|
95 |
+
def plugin_types(self) -> str | None: ...
|
96 |
+
@plugin_types.setter
|
97 |
+
def plugin_types(self, value: str | None) -> None: ...
|
98 |
+
@plugin_types.deleter
|
99 |
+
def plugin_types(self) -> None: ...
|
100 |
+
@property
|
101 |
+
def report_to(self) -> str | None: ...
|
102 |
+
@report_to.setter
|
103 |
+
def report_to(self, value: str | None) -> None: ...
|
104 |
+
@report_to.deleter
|
105 |
+
def report_to(self) -> None: ...
|
106 |
+
@property
|
107 |
+
def report_uri(self) -> str | None: ...
|
108 |
+
@report_uri.setter
|
109 |
+
def report_uri(self, value: str | None) -> None: ...
|
110 |
+
@report_uri.deleter
|
111 |
+
def report_uri(self) -> None: ...
|
112 |
+
@property
|
113 |
+
def sandbox(self) -> str | None: ...
|
114 |
+
@sandbox.setter
|
115 |
+
def sandbox(self, value: str | None) -> None: ...
|
116 |
+
@sandbox.deleter
|
117 |
+
def sandbox(self) -> None: ...
|
118 |
+
@property
|
119 |
+
def script_src(self) -> str | None: ...
|
120 |
+
@script_src.setter
|
121 |
+
def script_src(self, value: str | None) -> None: ...
|
122 |
+
@script_src.deleter
|
123 |
+
def script_src(self) -> None: ...
|
124 |
+
@property
|
125 |
+
def script_src_attr(self) -> str | None: ...
|
126 |
+
@script_src_attr.setter
|
127 |
+
def script_src_attr(self, value: str | None) -> None: ...
|
128 |
+
@script_src_attr.deleter
|
129 |
+
def script_src_attr(self) -> None: ...
|
130 |
+
@property
|
131 |
+
def script_src_elem(self) -> str | None: ...
|
132 |
+
@script_src_elem.setter
|
133 |
+
def script_src_elem(self, value: str | None) -> None: ...
|
134 |
+
@script_src_elem.deleter
|
135 |
+
def script_src_elem(self) -> None: ...
|
136 |
+
@property
|
137 |
+
def style_src(self) -> str | None: ...
|
138 |
+
@style_src.setter
|
139 |
+
def style_src(self, value: str | None) -> None: ...
|
140 |
+
@style_src.deleter
|
141 |
+
def style_src(self) -> None: ...
|
142 |
+
@property
|
143 |
+
def style_src_attr(self) -> str | None: ...
|
144 |
+
@style_src_attr.setter
|
145 |
+
def style_src_attr(self, value: str | None) -> None: ...
|
146 |
+
@style_src_attr.deleter
|
147 |
+
def style_src_attr(self) -> None: ...
|
148 |
+
@property
|
149 |
+
def style_src_elem(self) -> str | None: ...
|
150 |
+
@style_src_elem.setter
|
151 |
+
def style_src_elem(self, value: str | None) -> None: ...
|
152 |
+
@style_src_elem.deleter
|
153 |
+
def style_src_elem(self) -> None: ...
|
154 |
+
@property
|
155 |
+
def worker_src(self) -> str | None: ...
|
156 |
+
@worker_src.setter
|
157 |
+
def worker_src(self, value: str | None) -> None: ...
|
158 |
+
@worker_src.deleter
|
159 |
+
def worker_src(self) -> None: ...
|
160 |
+
provided: bool
|
161 |
+
def __init__(
|
162 |
+
self,
|
163 |
+
values: Mapping[str, str] | Iterable[tuple[str, str]] = (),
|
164 |
+
on_update: Callable[[ContentSecurityPolicy], None] | None = None,
|
165 |
+
) -> None: ...
|
166 |
+
def _get_value(self, key: str) -> str | None: ...
|
167 |
+
def _set_value(self, key: str, value: str) -> None: ...
|
168 |
+
def _del_value(self, key: str) -> None: ...
|
169 |
+
def to_header(self) -> str: ...
|
MLPY/Lib/site-packages/werkzeug/datastructures/etag.py
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from collections.abc import Collection
|
4 |
+
|
5 |
+
|
6 |
+
class ETags(Collection):
|
7 |
+
"""A set that can be used to check if one etag is present in a collection
|
8 |
+
of etags.
|
9 |
+
"""
|
10 |
+
|
11 |
+
def __init__(self, strong_etags=None, weak_etags=None, star_tag=False):
|
12 |
+
if not star_tag and strong_etags:
|
13 |
+
self._strong = frozenset(strong_etags)
|
14 |
+
else:
|
15 |
+
self._strong = frozenset()
|
16 |
+
|
17 |
+
self._weak = frozenset(weak_etags or ())
|
18 |
+
self.star_tag = star_tag
|
19 |
+
|
20 |
+
def as_set(self, include_weak=False):
|
21 |
+
"""Convert the `ETags` object into a python set. Per default all the
|
22 |
+
weak etags are not part of this set."""
|
23 |
+
rv = set(self._strong)
|
24 |
+
if include_weak:
|
25 |
+
rv.update(self._weak)
|
26 |
+
return rv
|
27 |
+
|
28 |
+
def is_weak(self, etag):
|
29 |
+
"""Check if an etag is weak."""
|
30 |
+
return etag in self._weak
|
31 |
+
|
32 |
+
def is_strong(self, etag):
|
33 |
+
"""Check if an etag is strong."""
|
34 |
+
return etag in self._strong
|
35 |
+
|
36 |
+
def contains_weak(self, etag):
|
37 |
+
"""Check if an etag is part of the set including weak and strong tags."""
|
38 |
+
return self.is_weak(etag) or self.contains(etag)
|
39 |
+
|
40 |
+
def contains(self, etag):
|
41 |
+
"""Check if an etag is part of the set ignoring weak tags.
|
42 |
+
It is also possible to use the ``in`` operator.
|
43 |
+
"""
|
44 |
+
if self.star_tag:
|
45 |
+
return True
|
46 |
+
return self.is_strong(etag)
|
47 |
+
|
48 |
+
def contains_raw(self, etag):
|
49 |
+
"""When passed a quoted tag it will check if this tag is part of the
|
50 |
+
set. If the tag is weak it is checked against weak and strong tags,
|
51 |
+
otherwise strong only."""
|
52 |
+
from ..http import unquote_etag
|
53 |
+
|
54 |
+
etag, weak = unquote_etag(etag)
|
55 |
+
if weak:
|
56 |
+
return self.contains_weak(etag)
|
57 |
+
return self.contains(etag)
|
58 |
+
|
59 |
+
def to_header(self):
|
60 |
+
"""Convert the etags set into a HTTP header string."""
|
61 |
+
if self.star_tag:
|
62 |
+
return "*"
|
63 |
+
return ", ".join(
|
64 |
+
[f'"{x}"' for x in self._strong] + [f'W/"{x}"' for x in self._weak]
|
65 |
+
)
|
66 |
+
|
67 |
+
def __call__(self, etag=None, data=None, include_weak=False):
|
68 |
+
if [etag, data].count(None) != 1:
|
69 |
+
raise TypeError("either tag or data required, but at least one")
|
70 |
+
if etag is None:
|
71 |
+
from ..http import generate_etag
|
72 |
+
|
73 |
+
etag = generate_etag(data)
|
74 |
+
if include_weak:
|
75 |
+
if etag in self._weak:
|
76 |
+
return True
|
77 |
+
return etag in self._strong
|
78 |
+
|
79 |
+
def __bool__(self):
|
80 |
+
return bool(self.star_tag or self._strong or self._weak)
|
81 |
+
|
82 |
+
def __str__(self):
|
83 |
+
return self.to_header()
|
84 |
+
|
85 |
+
def __len__(self):
|
86 |
+
return len(self._strong)
|
87 |
+
|
88 |
+
def __iter__(self):
|
89 |
+
return iter(self._strong)
|
90 |
+
|
91 |
+
def __contains__(self, etag):
|
92 |
+
return self.contains(etag)
|
93 |
+
|
94 |
+
def __repr__(self):
|
95 |
+
return f"<{type(self).__name__} {str(self)!r}>"
|
MLPY/Lib/site-packages/werkzeug/datastructures/etag.pyi
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections.abc import Collection
|
2 |
+
from collections.abc import Iterable
|
3 |
+
from collections.abc import Iterator
|
4 |
+
|
5 |
+
class ETags(Collection[str]):
|
6 |
+
_strong: frozenset[str]
|
7 |
+
_weak: frozenset[str]
|
8 |
+
star_tag: bool
|
9 |
+
def __init__(
|
10 |
+
self,
|
11 |
+
strong_etags: Iterable[str] | None = None,
|
12 |
+
weak_etags: Iterable[str] | None = None,
|
13 |
+
star_tag: bool = False,
|
14 |
+
) -> None: ...
|
15 |
+
def as_set(self, include_weak: bool = False) -> set[str]: ...
|
16 |
+
def is_weak(self, etag: str) -> bool: ...
|
17 |
+
def is_strong(self, etag: str) -> bool: ...
|
18 |
+
def contains_weak(self, etag: str) -> bool: ...
|
19 |
+
def contains(self, etag: str) -> bool: ...
|
20 |
+
def contains_raw(self, etag: str) -> bool: ...
|
21 |
+
def to_header(self) -> str: ...
|
22 |
+
def __call__(
|
23 |
+
self,
|
24 |
+
etag: str | None = None,
|
25 |
+
data: bytes | None = None,
|
26 |
+
include_weak: bool = False,
|
27 |
+
) -> bool: ...
|
28 |
+
def __len__(self) -> int: ...
|
29 |
+
def __iter__(self) -> Iterator[str]: ...
|
30 |
+
def __contains__(self, item: str) -> bool: ... # type: ignore
|
MLPY/Lib/site-packages/werkzeug/datastructures/file_storage.py
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import mimetypes
|
4 |
+
from io import BytesIO
|
5 |
+
from os import fsdecode
|
6 |
+
from os import fspath
|
7 |
+
|
8 |
+
from .._internal import _plain_int
|
9 |
+
from .structures import MultiDict
|
10 |
+
|
11 |
+
|
12 |
+
class FileStorage:
|
13 |
+
"""The :class:`FileStorage` class is a thin wrapper over incoming files.
|
14 |
+
It is used by the request object to represent uploaded files. All the
|
15 |
+
attributes of the wrapper stream are proxied by the file storage so
|
16 |
+
it's possible to do ``storage.read()`` instead of the long form
|
17 |
+
``storage.stream.read()``.
|
18 |
+
"""
|
19 |
+
|
20 |
+
def __init__(
|
21 |
+
self,
|
22 |
+
stream=None,
|
23 |
+
filename=None,
|
24 |
+
name=None,
|
25 |
+
content_type=None,
|
26 |
+
content_length=None,
|
27 |
+
headers=None,
|
28 |
+
):
|
29 |
+
self.name = name
|
30 |
+
self.stream = stream or BytesIO()
|
31 |
+
|
32 |
+
# If no filename is provided, attempt to get the filename from
|
33 |
+
# the stream object. Python names special streams like
|
34 |
+
# ``<stderr>`` with angular brackets, skip these streams.
|
35 |
+
if filename is None:
|
36 |
+
filename = getattr(stream, "name", None)
|
37 |
+
|
38 |
+
if filename is not None:
|
39 |
+
filename = fsdecode(filename)
|
40 |
+
|
41 |
+
if filename and filename[0] == "<" and filename[-1] == ">":
|
42 |
+
filename = None
|
43 |
+
else:
|
44 |
+
filename = fsdecode(filename)
|
45 |
+
|
46 |
+
self.filename = filename
|
47 |
+
|
48 |
+
if headers is None:
|
49 |
+
from .headers import Headers
|
50 |
+
|
51 |
+
headers = Headers()
|
52 |
+
self.headers = headers
|
53 |
+
if content_type is not None:
|
54 |
+
headers["Content-Type"] = content_type
|
55 |
+
if content_length is not None:
|
56 |
+
headers["Content-Length"] = str(content_length)
|
57 |
+
|
58 |
+
def _parse_content_type(self):
|
59 |
+
if not hasattr(self, "_parsed_content_type"):
|
60 |
+
self._parsed_content_type = http.parse_options_header(self.content_type)
|
61 |
+
|
62 |
+
@property
|
63 |
+
def content_type(self):
|
64 |
+
"""The content-type sent in the header. Usually not available"""
|
65 |
+
return self.headers.get("content-type")
|
66 |
+
|
67 |
+
@property
|
68 |
+
def content_length(self):
|
69 |
+
"""The content-length sent in the header. Usually not available"""
|
70 |
+
if "content-length" in self.headers:
|
71 |
+
try:
|
72 |
+
return _plain_int(self.headers["content-length"])
|
73 |
+
except ValueError:
|
74 |
+
pass
|
75 |
+
|
76 |
+
return 0
|
77 |
+
|
78 |
+
@property
|
79 |
+
def mimetype(self):
|
80 |
+
"""Like :attr:`content_type`, but without parameters (eg, without
|
81 |
+
charset, type etc.) and always lowercase. For example if the content
|
82 |
+
type is ``text/HTML; charset=utf-8`` the mimetype would be
|
83 |
+
``'text/html'``.
|
84 |
+
|
85 |
+
.. versionadded:: 0.7
|
86 |
+
"""
|
87 |
+
self._parse_content_type()
|
88 |
+
return self._parsed_content_type[0].lower()
|
89 |
+
|
90 |
+
@property
|
91 |
+
def mimetype_params(self):
|
92 |
+
"""The mimetype parameters as dict. For example if the content
|
93 |
+
type is ``text/html; charset=utf-8`` the params would be
|
94 |
+
``{'charset': 'utf-8'}``.
|
95 |
+
|
96 |
+
.. versionadded:: 0.7
|
97 |
+
"""
|
98 |
+
self._parse_content_type()
|
99 |
+
return self._parsed_content_type[1]
|
100 |
+
|
101 |
+
def save(self, dst, buffer_size=16384):
|
102 |
+
"""Save the file to a destination path or file object. If the
|
103 |
+
destination is a file object you have to close it yourself after the
|
104 |
+
call. The buffer size is the number of bytes held in memory during
|
105 |
+
the copy process. It defaults to 16KB.
|
106 |
+
|
107 |
+
For secure file saving also have a look at :func:`secure_filename`.
|
108 |
+
|
109 |
+
:param dst: a filename, :class:`os.PathLike`, or open file
|
110 |
+
object to write to.
|
111 |
+
:param buffer_size: Passed as the ``length`` parameter of
|
112 |
+
:func:`shutil.copyfileobj`.
|
113 |
+
|
114 |
+
.. versionchanged:: 1.0
|
115 |
+
Supports :mod:`pathlib`.
|
116 |
+
"""
|
117 |
+
from shutil import copyfileobj
|
118 |
+
|
119 |
+
close_dst = False
|
120 |
+
|
121 |
+
if hasattr(dst, "__fspath__"):
|
122 |
+
dst = fspath(dst)
|
123 |
+
|
124 |
+
if isinstance(dst, str):
|
125 |
+
dst = open(dst, "wb")
|
126 |
+
close_dst = True
|
127 |
+
|
128 |
+
try:
|
129 |
+
copyfileobj(self.stream, dst, buffer_size)
|
130 |
+
finally:
|
131 |
+
if close_dst:
|
132 |
+
dst.close()
|
133 |
+
|
134 |
+
def close(self):
|
135 |
+
"""Close the underlying file if possible."""
|
136 |
+
try:
|
137 |
+
self.stream.close()
|
138 |
+
except Exception:
|
139 |
+
pass
|
140 |
+
|
141 |
+
def __bool__(self):
|
142 |
+
return bool(self.filename)
|
143 |
+
|
144 |
+
def __getattr__(self, name):
|
145 |
+
try:
|
146 |
+
return getattr(self.stream, name)
|
147 |
+
except AttributeError:
|
148 |
+
# SpooledTemporaryFile doesn't implement IOBase, get the
|
149 |
+
# attribute from its backing file instead.
|
150 |
+
# https://github.com/python/cpython/pull/3249
|
151 |
+
if hasattr(self.stream, "_file"):
|
152 |
+
return getattr(self.stream._file, name)
|
153 |
+
raise
|
154 |
+
|
155 |
+
def __iter__(self):
|
156 |
+
return iter(self.stream)
|
157 |
+
|
158 |
+
def __repr__(self):
|
159 |
+
return f"<{type(self).__name__}: {self.filename!r} ({self.content_type!r})>"
|
160 |
+
|
161 |
+
|
162 |
+
class FileMultiDict(MultiDict):
|
163 |
+
"""A special :class:`MultiDict` that has convenience methods to add
|
164 |
+
files to it. This is used for :class:`EnvironBuilder` and generally
|
165 |
+
useful for unittesting.
|
166 |
+
|
167 |
+
.. versionadded:: 0.5
|
168 |
+
"""
|
169 |
+
|
170 |
+
def add_file(self, name, file, filename=None, content_type=None):
|
171 |
+
"""Adds a new file to the dict. `file` can be a file name or
|
172 |
+
a :class:`file`-like or a :class:`FileStorage` object.
|
173 |
+
|
174 |
+
:param name: the name of the field.
|
175 |
+
:param file: a filename or :class:`file`-like object
|
176 |
+
:param filename: an optional filename
|
177 |
+
:param content_type: an optional content type
|
178 |
+
"""
|
179 |
+
if isinstance(file, FileStorage):
|
180 |
+
value = file
|
181 |
+
else:
|
182 |
+
if isinstance(file, str):
|
183 |
+
if filename is None:
|
184 |
+
filename = file
|
185 |
+
file = open(file, "rb")
|
186 |
+
if filename and content_type is None:
|
187 |
+
content_type = (
|
188 |
+
mimetypes.guess_type(filename)[0] or "application/octet-stream"
|
189 |
+
)
|
190 |
+
value = FileStorage(file, filename, name, content_type)
|
191 |
+
|
192 |
+
self.add(name, value)
|
193 |
+
|
194 |
+
|
195 |
+
# circular dependencies
|
196 |
+
from .. import http
|
MLPY/Lib/site-packages/werkzeug/datastructures/file_storage.pyi
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections.abc import Iterator
|
2 |
+
from os import PathLike
|
3 |
+
from typing import Any
|
4 |
+
from typing import IO
|
5 |
+
|
6 |
+
from .headers import Headers
|
7 |
+
from .structures import MultiDict
|
8 |
+
|
9 |
+
class FileStorage:
|
10 |
+
name: str | None
|
11 |
+
stream: IO[bytes]
|
12 |
+
filename: str | None
|
13 |
+
headers: Headers
|
14 |
+
_parsed_content_type: tuple[str, dict[str, str]]
|
15 |
+
def __init__(
|
16 |
+
self,
|
17 |
+
stream: IO[bytes] | None = None,
|
18 |
+
filename: str | PathLike[str] | None = None,
|
19 |
+
name: str | None = None,
|
20 |
+
content_type: str | None = None,
|
21 |
+
content_length: int | None = None,
|
22 |
+
headers: Headers | None = None,
|
23 |
+
) -> None: ...
|
24 |
+
def _parse_content_type(self) -> None: ...
|
25 |
+
@property
|
26 |
+
def content_type(self) -> str: ...
|
27 |
+
@property
|
28 |
+
def content_length(self) -> int: ...
|
29 |
+
@property
|
30 |
+
def mimetype(self) -> str: ...
|
31 |
+
@property
|
32 |
+
def mimetype_params(self) -> dict[str, str]: ...
|
33 |
+
def save(
|
34 |
+
self, dst: str | PathLike[str] | IO[bytes], buffer_size: int = ...
|
35 |
+
) -> None: ...
|
36 |
+
def close(self) -> None: ...
|
37 |
+
def __bool__(self) -> bool: ...
|
38 |
+
def __getattr__(self, name: str) -> Any: ...
|
39 |
+
def __iter__(self) -> Iterator[bytes]: ...
|
40 |
+
def __repr__(self) -> str: ...
|
41 |
+
|
42 |
+
class FileMultiDict(MultiDict[str, FileStorage]):
|
43 |
+
def add_file(
|
44 |
+
self,
|
45 |
+
name: str,
|
46 |
+
file: FileStorage | str | IO[bytes],
|
47 |
+
filename: str | None = None,
|
48 |
+
content_type: str | None = None,
|
49 |
+
) -> None: ...
|
MLPY/Lib/site-packages/werkzeug/datastructures/headers.py
ADDED
@@ -0,0 +1,515 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import re
|
4 |
+
import typing as t
|
5 |
+
|
6 |
+
from .._internal import _missing
|
7 |
+
from ..exceptions import BadRequestKeyError
|
8 |
+
from .mixins import ImmutableHeadersMixin
|
9 |
+
from .structures import iter_multi_items
|
10 |
+
from .structures import MultiDict
|
11 |
+
|
12 |
+
|
13 |
+
class Headers:
|
14 |
+
"""An object that stores some headers. It has a dict-like interface,
|
15 |
+
but is ordered, can store the same key multiple times, and iterating
|
16 |
+
yields ``(key, value)`` pairs instead of only keys.
|
17 |
+
|
18 |
+
This data structure is useful if you want a nicer way to handle WSGI
|
19 |
+
headers which are stored as tuples in a list.
|
20 |
+
|
21 |
+
From Werkzeug 0.3 onwards, the :exc:`KeyError` raised by this class is
|
22 |
+
also a subclass of the :class:`~exceptions.BadRequest` HTTP exception
|
23 |
+
and will render a page for a ``400 BAD REQUEST`` if caught in a
|
24 |
+
catch-all for HTTP exceptions.
|
25 |
+
|
26 |
+
Headers is mostly compatible with the Python :class:`wsgiref.headers.Headers`
|
27 |
+
class, with the exception of `__getitem__`. :mod:`wsgiref` will return
|
28 |
+
`None` for ``headers['missing']``, whereas :class:`Headers` will raise
|
29 |
+
a :class:`KeyError`.
|
30 |
+
|
31 |
+
To create a new ``Headers`` object, pass it a list, dict, or
|
32 |
+
other ``Headers`` object with default values. These values are
|
33 |
+
validated the same way values added later are.
|
34 |
+
|
35 |
+
:param defaults: The list of default values for the :class:`Headers`.
|
36 |
+
|
37 |
+
.. versionchanged:: 2.1.0
|
38 |
+
Default values are validated the same as values added later.
|
39 |
+
|
40 |
+
.. versionchanged:: 0.9
|
41 |
+
This data structure now stores unicode values similar to how the
|
42 |
+
multi dicts do it. The main difference is that bytes can be set as
|
43 |
+
well which will automatically be latin1 decoded.
|
44 |
+
|
45 |
+
.. versionchanged:: 0.9
|
46 |
+
The :meth:`linked` function was removed without replacement as it
|
47 |
+
was an API that does not support the changes to the encoding model.
|
48 |
+
"""
|
49 |
+
|
50 |
+
def __init__(self, defaults=None):
|
51 |
+
self._list = []
|
52 |
+
if defaults is not None:
|
53 |
+
self.extend(defaults)
|
54 |
+
|
55 |
+
def __getitem__(self, key, _get_mode=False):
|
56 |
+
if not _get_mode:
|
57 |
+
if isinstance(key, int):
|
58 |
+
return self._list[key]
|
59 |
+
elif isinstance(key, slice):
|
60 |
+
return self.__class__(self._list[key])
|
61 |
+
if not isinstance(key, str):
|
62 |
+
raise BadRequestKeyError(key)
|
63 |
+
ikey = key.lower()
|
64 |
+
for k, v in self._list:
|
65 |
+
if k.lower() == ikey:
|
66 |
+
return v
|
67 |
+
# micro optimization: if we are in get mode we will catch that
|
68 |
+
# exception one stack level down so we can raise a standard
|
69 |
+
# key error instead of our special one.
|
70 |
+
if _get_mode:
|
71 |
+
raise KeyError()
|
72 |
+
raise BadRequestKeyError(key)
|
73 |
+
|
74 |
+
def __eq__(self, other):
|
75 |
+
def lowered(item):
|
76 |
+
return (item[0].lower(),) + item[1:]
|
77 |
+
|
78 |
+
return other.__class__ is self.__class__ and set(
|
79 |
+
map(lowered, other._list)
|
80 |
+
) == set(map(lowered, self._list))
|
81 |
+
|
82 |
+
__hash__ = None
|
83 |
+
|
84 |
+
def get(self, key, default=None, type=None):
|
85 |
+
"""Return the default value if the requested data doesn't exist.
|
86 |
+
If `type` is provided and is a callable it should convert the value,
|
87 |
+
return it or raise a :exc:`ValueError` if that is not possible. In
|
88 |
+
this case the function will return the default as if the value was not
|
89 |
+
found:
|
90 |
+
|
91 |
+
>>> d = Headers([('Content-Length', '42')])
|
92 |
+
>>> d.get('Content-Length', type=int)
|
93 |
+
42
|
94 |
+
|
95 |
+
:param key: The key to be looked up.
|
96 |
+
:param default: The default value to be returned if the key can't
|
97 |
+
be looked up. If not further specified `None` is
|
98 |
+
returned.
|
99 |
+
:param type: A callable that is used to cast the value in the
|
100 |
+
:class:`Headers`. If a :exc:`ValueError` is raised
|
101 |
+
by this callable the default value is returned.
|
102 |
+
|
103 |
+
.. versionchanged:: 3.0
|
104 |
+
The ``as_bytes`` parameter was removed.
|
105 |
+
|
106 |
+
.. versionchanged:: 0.9
|
107 |
+
The ``as_bytes`` parameter was added.
|
108 |
+
"""
|
109 |
+
try:
|
110 |
+
rv = self.__getitem__(key, _get_mode=True)
|
111 |
+
except KeyError:
|
112 |
+
return default
|
113 |
+
if type is None:
|
114 |
+
return rv
|
115 |
+
try:
|
116 |
+
return type(rv)
|
117 |
+
except ValueError:
|
118 |
+
return default
|
119 |
+
|
120 |
+
def getlist(self, key, type=None):
|
121 |
+
"""Return the list of items for a given key. If that key is not in the
|
122 |
+
:class:`Headers`, the return value will be an empty list. Just like
|
123 |
+
:meth:`get`, :meth:`getlist` accepts a `type` parameter. All items will
|
124 |
+
be converted with the callable defined there.
|
125 |
+
|
126 |
+
:param key: The key to be looked up.
|
127 |
+
:param type: A callable that is used to cast the value in the
|
128 |
+
:class:`Headers`. If a :exc:`ValueError` is raised
|
129 |
+
by this callable the value will be removed from the list.
|
130 |
+
:return: a :class:`list` of all the values for the key.
|
131 |
+
|
132 |
+
.. versionchanged:: 3.0
|
133 |
+
The ``as_bytes`` parameter was removed.
|
134 |
+
|
135 |
+
.. versionchanged:: 0.9
|
136 |
+
The ``as_bytes`` parameter was added.
|
137 |
+
"""
|
138 |
+
ikey = key.lower()
|
139 |
+
result = []
|
140 |
+
for k, v in self:
|
141 |
+
if k.lower() == ikey:
|
142 |
+
if type is not None:
|
143 |
+
try:
|
144 |
+
v = type(v)
|
145 |
+
except ValueError:
|
146 |
+
continue
|
147 |
+
result.append(v)
|
148 |
+
return result
|
149 |
+
|
150 |
+
def get_all(self, name):
|
151 |
+
"""Return a list of all the values for the named field.
|
152 |
+
|
153 |
+
This method is compatible with the :mod:`wsgiref`
|
154 |
+
:meth:`~wsgiref.headers.Headers.get_all` method.
|
155 |
+
"""
|
156 |
+
return self.getlist(name)
|
157 |
+
|
158 |
+
def items(self, lower=False):
|
159 |
+
for key, value in self:
|
160 |
+
if lower:
|
161 |
+
key = key.lower()
|
162 |
+
yield key, value
|
163 |
+
|
164 |
+
def keys(self, lower=False):
|
165 |
+
for key, _ in self.items(lower):
|
166 |
+
yield key
|
167 |
+
|
168 |
+
def values(self):
|
169 |
+
for _, value in self.items():
|
170 |
+
yield value
|
171 |
+
|
172 |
+
def extend(self, *args, **kwargs):
|
173 |
+
"""Extend headers in this object with items from another object
|
174 |
+
containing header items as well as keyword arguments.
|
175 |
+
|
176 |
+
To replace existing keys instead of extending, use
|
177 |
+
:meth:`update` instead.
|
178 |
+
|
179 |
+
If provided, the first argument can be another :class:`Headers`
|
180 |
+
object, a :class:`MultiDict`, :class:`dict`, or iterable of
|
181 |
+
pairs.
|
182 |
+
|
183 |
+
.. versionchanged:: 1.0
|
184 |
+
Support :class:`MultiDict`. Allow passing ``kwargs``.
|
185 |
+
"""
|
186 |
+
if len(args) > 1:
|
187 |
+
raise TypeError(f"update expected at most 1 arguments, got {len(args)}")
|
188 |
+
|
189 |
+
if args:
|
190 |
+
for key, value in iter_multi_items(args[0]):
|
191 |
+
self.add(key, value)
|
192 |
+
|
193 |
+
for key, value in iter_multi_items(kwargs):
|
194 |
+
self.add(key, value)
|
195 |
+
|
196 |
+
def __delitem__(self, key, _index_operation=True):
|
197 |
+
if _index_operation and isinstance(key, (int, slice)):
|
198 |
+
del self._list[key]
|
199 |
+
return
|
200 |
+
key = key.lower()
|
201 |
+
new = []
|
202 |
+
for k, v in self._list:
|
203 |
+
if k.lower() != key:
|
204 |
+
new.append((k, v))
|
205 |
+
self._list[:] = new
|
206 |
+
|
207 |
+
def remove(self, key):
|
208 |
+
"""Remove a key.
|
209 |
+
|
210 |
+
:param key: The key to be removed.
|
211 |
+
"""
|
212 |
+
return self.__delitem__(key, _index_operation=False)
|
213 |
+
|
214 |
+
def pop(self, key=None, default=_missing):
|
215 |
+
"""Removes and returns a key or index.
|
216 |
+
|
217 |
+
:param key: The key to be popped. If this is an integer the item at
|
218 |
+
that position is removed, if it's a string the value for
|
219 |
+
that key is. If the key is omitted or `None` the last
|
220 |
+
item is removed.
|
221 |
+
:return: an item.
|
222 |
+
"""
|
223 |
+
if key is None:
|
224 |
+
return self._list.pop()
|
225 |
+
if isinstance(key, int):
|
226 |
+
return self._list.pop(key)
|
227 |
+
try:
|
228 |
+
rv = self[key]
|
229 |
+
self.remove(key)
|
230 |
+
except KeyError:
|
231 |
+
if default is not _missing:
|
232 |
+
return default
|
233 |
+
raise
|
234 |
+
return rv
|
235 |
+
|
236 |
+
def popitem(self):
|
237 |
+
"""Removes a key or index and returns a (key, value) item."""
|
238 |
+
return self.pop()
|
239 |
+
|
240 |
+
def __contains__(self, key):
|
241 |
+
"""Check if a key is present."""
|
242 |
+
try:
|
243 |
+
self.__getitem__(key, _get_mode=True)
|
244 |
+
except KeyError:
|
245 |
+
return False
|
246 |
+
return True
|
247 |
+
|
248 |
+
def __iter__(self):
|
249 |
+
"""Yield ``(key, value)`` tuples."""
|
250 |
+
return iter(self._list)
|
251 |
+
|
252 |
+
def __len__(self):
|
253 |
+
return len(self._list)
|
254 |
+
|
255 |
+
def add(self, _key, _value, **kw):
|
256 |
+
"""Add a new header tuple to the list.
|
257 |
+
|
258 |
+
Keyword arguments can specify additional parameters for the header
|
259 |
+
value, with underscores converted to dashes::
|
260 |
+
|
261 |
+
>>> d = Headers()
|
262 |
+
>>> d.add('Content-Type', 'text/plain')
|
263 |
+
>>> d.add('Content-Disposition', 'attachment', filename='foo.png')
|
264 |
+
|
265 |
+
The keyword argument dumping uses :func:`dump_options_header`
|
266 |
+
behind the scenes.
|
267 |
+
|
268 |
+
.. versionadded:: 0.4.1
|
269 |
+
keyword arguments were added for :mod:`wsgiref` compatibility.
|
270 |
+
"""
|
271 |
+
if kw:
|
272 |
+
_value = _options_header_vkw(_value, kw)
|
273 |
+
_value = _str_header_value(_value)
|
274 |
+
self._list.append((_key, _value))
|
275 |
+
|
276 |
+
def add_header(self, _key, _value, **_kw):
|
277 |
+
"""Add a new header tuple to the list.
|
278 |
+
|
279 |
+
An alias for :meth:`add` for compatibility with the :mod:`wsgiref`
|
280 |
+
:meth:`~wsgiref.headers.Headers.add_header` method.
|
281 |
+
"""
|
282 |
+
self.add(_key, _value, **_kw)
|
283 |
+
|
284 |
+
def clear(self):
|
285 |
+
"""Clears all headers."""
|
286 |
+
del self._list[:]
|
287 |
+
|
288 |
+
def set(self, _key, _value, **kw):
|
289 |
+
"""Remove all header tuples for `key` and add a new one. The newly
|
290 |
+
added key either appears at the end of the list if there was no
|
291 |
+
entry or replaces the first one.
|
292 |
+
|
293 |
+
Keyword arguments can specify additional parameters for the header
|
294 |
+
value, with underscores converted to dashes. See :meth:`add` for
|
295 |
+
more information.
|
296 |
+
|
297 |
+
.. versionchanged:: 0.6.1
|
298 |
+
:meth:`set` now accepts the same arguments as :meth:`add`.
|
299 |
+
|
300 |
+
:param key: The key to be inserted.
|
301 |
+
:param value: The value to be inserted.
|
302 |
+
"""
|
303 |
+
if kw:
|
304 |
+
_value = _options_header_vkw(_value, kw)
|
305 |
+
_value = _str_header_value(_value)
|
306 |
+
if not self._list:
|
307 |
+
self._list.append((_key, _value))
|
308 |
+
return
|
309 |
+
listiter = iter(self._list)
|
310 |
+
ikey = _key.lower()
|
311 |
+
for idx, (old_key, _old_value) in enumerate(listiter):
|
312 |
+
if old_key.lower() == ikey:
|
313 |
+
# replace first occurrence
|
314 |
+
self._list[idx] = (_key, _value)
|
315 |
+
break
|
316 |
+
else:
|
317 |
+
self._list.append((_key, _value))
|
318 |
+
return
|
319 |
+
self._list[idx + 1 :] = [t for t in listiter if t[0].lower() != ikey]
|
320 |
+
|
321 |
+
def setlist(self, key, values):
|
322 |
+
"""Remove any existing values for a header and add new ones.
|
323 |
+
|
324 |
+
:param key: The header key to set.
|
325 |
+
:param values: An iterable of values to set for the key.
|
326 |
+
|
327 |
+
.. versionadded:: 1.0
|
328 |
+
"""
|
329 |
+
if values:
|
330 |
+
values_iter = iter(values)
|
331 |
+
self.set(key, next(values_iter))
|
332 |
+
|
333 |
+
for value in values_iter:
|
334 |
+
self.add(key, value)
|
335 |
+
else:
|
336 |
+
self.remove(key)
|
337 |
+
|
338 |
+
def setdefault(self, key, default):
|
339 |
+
"""Return the first value for the key if it is in the headers,
|
340 |
+
otherwise set the header to the value given by ``default`` and
|
341 |
+
return that.
|
342 |
+
|
343 |
+
:param key: The header key to get.
|
344 |
+
:param default: The value to set for the key if it is not in the
|
345 |
+
headers.
|
346 |
+
"""
|
347 |
+
if key in self:
|
348 |
+
return self[key]
|
349 |
+
|
350 |
+
self.set(key, default)
|
351 |
+
return default
|
352 |
+
|
353 |
+
def setlistdefault(self, key, default):
|
354 |
+
"""Return the list of values for the key if it is in the
|
355 |
+
headers, otherwise set the header to the list of values given
|
356 |
+
by ``default`` and return that.
|
357 |
+
|
358 |
+
Unlike :meth:`MultiDict.setlistdefault`, modifying the returned
|
359 |
+
list will not affect the headers.
|
360 |
+
|
361 |
+
:param key: The header key to get.
|
362 |
+
:param default: An iterable of values to set for the key if it
|
363 |
+
is not in the headers.
|
364 |
+
|
365 |
+
.. versionadded:: 1.0
|
366 |
+
"""
|
367 |
+
if key not in self:
|
368 |
+
self.setlist(key, default)
|
369 |
+
|
370 |
+
return self.getlist(key)
|
371 |
+
|
372 |
+
def __setitem__(self, key, value):
|
373 |
+
"""Like :meth:`set` but also supports index/slice based setting."""
|
374 |
+
if isinstance(key, (slice, int)):
|
375 |
+
if isinstance(key, int):
|
376 |
+
value = [value]
|
377 |
+
value = [(k, _str_header_value(v)) for (k, v) in value]
|
378 |
+
if isinstance(key, int):
|
379 |
+
self._list[key] = value[0]
|
380 |
+
else:
|
381 |
+
self._list[key] = value
|
382 |
+
else:
|
383 |
+
self.set(key, value)
|
384 |
+
|
385 |
+
def update(self, *args, **kwargs):
|
386 |
+
"""Replace headers in this object with items from another
|
387 |
+
headers object and keyword arguments.
|
388 |
+
|
389 |
+
To extend existing keys instead of replacing, use :meth:`extend`
|
390 |
+
instead.
|
391 |
+
|
392 |
+
If provided, the first argument can be another :class:`Headers`
|
393 |
+
object, a :class:`MultiDict`, :class:`dict`, or iterable of
|
394 |
+
pairs.
|
395 |
+
|
396 |
+
.. versionadded:: 1.0
|
397 |
+
"""
|
398 |
+
if len(args) > 1:
|
399 |
+
raise TypeError(f"update expected at most 1 arguments, got {len(args)}")
|
400 |
+
|
401 |
+
if args:
|
402 |
+
mapping = args[0]
|
403 |
+
|
404 |
+
if isinstance(mapping, (Headers, MultiDict)):
|
405 |
+
for key in mapping.keys():
|
406 |
+
self.setlist(key, mapping.getlist(key))
|
407 |
+
elif isinstance(mapping, dict):
|
408 |
+
for key, value in mapping.items():
|
409 |
+
if isinstance(value, (list, tuple)):
|
410 |
+
self.setlist(key, value)
|
411 |
+
else:
|
412 |
+
self.set(key, value)
|
413 |
+
else:
|
414 |
+
for key, value in mapping:
|
415 |
+
self.set(key, value)
|
416 |
+
|
417 |
+
for key, value in kwargs.items():
|
418 |
+
if isinstance(value, (list, tuple)):
|
419 |
+
self.setlist(key, value)
|
420 |
+
else:
|
421 |
+
self.set(key, value)
|
422 |
+
|
423 |
+
def to_wsgi_list(self):
|
424 |
+
"""Convert the headers into a list suitable for WSGI.
|
425 |
+
|
426 |
+
:return: list
|
427 |
+
"""
|
428 |
+
return list(self)
|
429 |
+
|
430 |
+
def copy(self):
|
431 |
+
return self.__class__(self._list)
|
432 |
+
|
433 |
+
def __copy__(self):
|
434 |
+
return self.copy()
|
435 |
+
|
436 |
+
def __str__(self):
|
437 |
+
"""Returns formatted headers suitable for HTTP transmission."""
|
438 |
+
strs = []
|
439 |
+
for key, value in self.to_wsgi_list():
|
440 |
+
strs.append(f"{key}: {value}")
|
441 |
+
strs.append("\r\n")
|
442 |
+
return "\r\n".join(strs)
|
443 |
+
|
444 |
+
def __repr__(self):
|
445 |
+
return f"{type(self).__name__}({list(self)!r})"
|
446 |
+
|
447 |
+
|
448 |
+
def _options_header_vkw(value: str, kw: dict[str, t.Any]):
|
449 |
+
return http.dump_options_header(
|
450 |
+
value, {k.replace("_", "-"): v for k, v in kw.items()}
|
451 |
+
)
|
452 |
+
|
453 |
+
|
454 |
+
_newline_re = re.compile(r"[\r\n]")
|
455 |
+
|
456 |
+
|
457 |
+
def _str_header_value(value: t.Any) -> str:
|
458 |
+
if not isinstance(value, str):
|
459 |
+
value = str(value)
|
460 |
+
|
461 |
+
if _newline_re.search(value) is not None:
|
462 |
+
raise ValueError("Header values must not contain newline characters.")
|
463 |
+
|
464 |
+
return value
|
465 |
+
|
466 |
+
|
467 |
+
class EnvironHeaders(ImmutableHeadersMixin, Headers):
|
468 |
+
"""Read only version of the headers from a WSGI environment. This
|
469 |
+
provides the same interface as `Headers` and is constructed from
|
470 |
+
a WSGI environment.
|
471 |
+
From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
|
472 |
+
subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
|
473 |
+
render a page for a ``400 BAD REQUEST`` if caught in a catch-all for
|
474 |
+
HTTP exceptions.
|
475 |
+
"""
|
476 |
+
|
477 |
+
def __init__(self, environ):
|
478 |
+
self.environ = environ
|
479 |
+
|
480 |
+
def __eq__(self, other):
|
481 |
+
return self.environ is other.environ
|
482 |
+
|
483 |
+
__hash__ = None
|
484 |
+
|
485 |
+
def __getitem__(self, key, _get_mode=False):
|
486 |
+
# _get_mode is a no-op for this class as there is no index but
|
487 |
+
# used because get() calls it.
|
488 |
+
if not isinstance(key, str):
|
489 |
+
raise KeyError(key)
|
490 |
+
key = key.upper().replace("-", "_")
|
491 |
+
if key in {"CONTENT_TYPE", "CONTENT_LENGTH"}:
|
492 |
+
return self.environ[key]
|
493 |
+
return self.environ[f"HTTP_{key}"]
|
494 |
+
|
495 |
+
def __len__(self):
|
496 |
+
# the iter is necessary because otherwise list calls our
|
497 |
+
# len which would call list again and so forth.
|
498 |
+
return len(list(iter(self)))
|
499 |
+
|
500 |
+
def __iter__(self):
|
501 |
+
for key, value in self.environ.items():
|
502 |
+
if key.startswith("HTTP_") and key not in {
|
503 |
+
"HTTP_CONTENT_TYPE",
|
504 |
+
"HTTP_CONTENT_LENGTH",
|
505 |
+
}:
|
506 |
+
yield key[5:].replace("_", "-").title(), value
|
507 |
+
elif key in {"CONTENT_TYPE", "CONTENT_LENGTH"} and value:
|
508 |
+
yield key.replace("_", "-").title(), value
|
509 |
+
|
510 |
+
def copy(self):
|
511 |
+
raise TypeError(f"cannot create {type(self).__name__!r} copies")
|
512 |
+
|
513 |
+
|
514 |
+
# circular dependencies
|
515 |
+
from .. import http
|
MLPY/Lib/site-packages/werkzeug/datastructures/headers.pyi
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections.abc import Callable
|
2 |
+
from collections.abc import Iterable
|
3 |
+
from collections.abc import Iterator
|
4 |
+
from collections.abc import Mapping
|
5 |
+
from typing import Literal
|
6 |
+
from typing import NoReturn
|
7 |
+
from typing import overload
|
8 |
+
from typing import TypeVar
|
9 |
+
|
10 |
+
from _typeshed import SupportsKeysAndGetItem
|
11 |
+
from _typeshed.wsgi import WSGIEnvironment
|
12 |
+
|
13 |
+
from .mixins import ImmutableHeadersMixin
|
14 |
+
|
15 |
+
D = TypeVar("D")
|
16 |
+
T = TypeVar("T")
|
17 |
+
|
18 |
+
class Headers(dict[str, str]):
|
19 |
+
_list: list[tuple[str, str]]
|
20 |
+
def __init__(
|
21 |
+
self,
|
22 |
+
defaults: Mapping[str, str | Iterable[str]]
|
23 |
+
| Iterable[tuple[str, str]]
|
24 |
+
| None = None,
|
25 |
+
) -> None: ...
|
26 |
+
@overload
|
27 |
+
def __getitem__(self, key: str) -> str: ...
|
28 |
+
@overload
|
29 |
+
def __getitem__(self, key: int) -> tuple[str, str]: ...
|
30 |
+
@overload
|
31 |
+
def __getitem__(self, key: slice) -> Headers: ...
|
32 |
+
@overload
|
33 |
+
def __getitem__(self, key: str, _get_mode: Literal[True] = ...) -> str: ...
|
34 |
+
def __eq__(self, other: object) -> bool: ...
|
35 |
+
@overload # type: ignore
|
36 |
+
def get(self, key: str, default: str) -> str: ...
|
37 |
+
@overload
|
38 |
+
def get(self, key: str, default: str | None = None) -> str | None: ...
|
39 |
+
@overload
|
40 |
+
def get(
|
41 |
+
self, key: str, default: T | None = None, type: Callable[[str], T] = ...
|
42 |
+
) -> T | None: ...
|
43 |
+
@overload
|
44 |
+
def getlist(self, key: str) -> list[str]: ...
|
45 |
+
@overload
|
46 |
+
def getlist(self, key: str, type: Callable[[str], T]) -> list[T]: ...
|
47 |
+
def get_all(self, name: str) -> list[str]: ...
|
48 |
+
def items( # type: ignore
|
49 |
+
self, lower: bool = False
|
50 |
+
) -> Iterator[tuple[str, str]]: ...
|
51 |
+
def keys(self, lower: bool = False) -> Iterator[str]: ... # type: ignore
|
52 |
+
def values(self) -> Iterator[str]: ... # type: ignore
|
53 |
+
def extend(
|
54 |
+
self,
|
55 |
+
*args: Mapping[str, str | Iterable[str]] | Iterable[tuple[str, str]],
|
56 |
+
**kwargs: str | Iterable[str],
|
57 |
+
) -> None: ...
|
58 |
+
@overload
|
59 |
+
def __delitem__(self, key: str | int | slice) -> None: ...
|
60 |
+
@overload
|
61 |
+
def __delitem__(self, key: str, _index_operation: Literal[False]) -> None: ...
|
62 |
+
def remove(self, key: str) -> None: ...
|
63 |
+
@overload # type: ignore
|
64 |
+
def pop(self, key: str, default: str | None = None) -> str: ...
|
65 |
+
@overload
|
66 |
+
def pop(
|
67 |
+
self, key: int | None = None, default: tuple[str, str] | None = None
|
68 |
+
) -> tuple[str, str]: ...
|
69 |
+
def popitem(self) -> tuple[str, str]: ...
|
70 |
+
def __contains__(self, key: str) -> bool: ... # type: ignore
|
71 |
+
def has_key(self, key: str) -> bool: ...
|
72 |
+
def __iter__(self) -> Iterator[tuple[str, str]]: ... # type: ignore
|
73 |
+
def add(self, _key: str, _value: str, **kw: str) -> None: ...
|
74 |
+
def _validate_value(self, value: str) -> None: ...
|
75 |
+
def add_header(self, _key: str, _value: str, **_kw: str) -> None: ...
|
76 |
+
def clear(self) -> None: ...
|
77 |
+
def set(self, _key: str, _value: str, **kw: str) -> None: ...
|
78 |
+
def setlist(self, key: str, values: Iterable[str]) -> None: ...
|
79 |
+
def setdefault(self, key: str, default: str) -> str: ...
|
80 |
+
def setlistdefault(self, key: str, default: Iterable[str]) -> None: ...
|
81 |
+
@overload
|
82 |
+
def __setitem__(self, key: str, value: str) -> None: ...
|
83 |
+
@overload
|
84 |
+
def __setitem__(self, key: int, value: tuple[str, str]) -> None: ...
|
85 |
+
@overload
|
86 |
+
def __setitem__(self, key: slice, value: Iterable[tuple[str, str]]) -> None: ...
|
87 |
+
@overload
|
88 |
+
def update(
|
89 |
+
self, __m: SupportsKeysAndGetItem[str, str], **kwargs: str | Iterable[str]
|
90 |
+
) -> None: ...
|
91 |
+
@overload
|
92 |
+
def update(
|
93 |
+
self, __m: Iterable[tuple[str, str]], **kwargs: str | Iterable[str]
|
94 |
+
) -> None: ...
|
95 |
+
@overload
|
96 |
+
def update(self, **kwargs: str | Iterable[str]) -> None: ...
|
97 |
+
def to_wsgi_list(self) -> list[tuple[str, str]]: ...
|
98 |
+
def copy(self) -> Headers: ...
|
99 |
+
def __copy__(self) -> Headers: ...
|
100 |
+
|
101 |
+
class EnvironHeaders(ImmutableHeadersMixin, Headers):
|
102 |
+
environ: WSGIEnvironment
|
103 |
+
def __init__(self, environ: WSGIEnvironment) -> None: ...
|
104 |
+
def __eq__(self, other: object) -> bool: ...
|
105 |
+
def __getitem__( # type: ignore
|
106 |
+
self, key: str, _get_mode: Literal[False] = False
|
107 |
+
) -> str: ...
|
108 |
+
def __iter__(self) -> Iterator[tuple[str, str]]: ... # type: ignore
|
109 |
+
def copy(self) -> NoReturn: ...
|
MLPY/Lib/site-packages/werkzeug/datastructures/mixins.py
ADDED
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from itertools import repeat
|
4 |
+
|
5 |
+
from .._internal import _missing
|
6 |
+
|
7 |
+
|
8 |
+
def is_immutable(self):
|
9 |
+
raise TypeError(f"{type(self).__name__!r} objects are immutable")
|
10 |
+
|
11 |
+
|
12 |
+
class ImmutableListMixin:
|
13 |
+
"""Makes a :class:`list` immutable.
|
14 |
+
|
15 |
+
.. versionadded:: 0.5
|
16 |
+
|
17 |
+
:private:
|
18 |
+
"""
|
19 |
+
|
20 |
+
_hash_cache = None
|
21 |
+
|
22 |
+
def __hash__(self):
|
23 |
+
if self._hash_cache is not None:
|
24 |
+
return self._hash_cache
|
25 |
+
rv = self._hash_cache = hash(tuple(self))
|
26 |
+
return rv
|
27 |
+
|
28 |
+
def __reduce_ex__(self, protocol):
|
29 |
+
return type(self), (list(self),)
|
30 |
+
|
31 |
+
def __delitem__(self, key):
|
32 |
+
is_immutable(self)
|
33 |
+
|
34 |
+
def __iadd__(self, other):
|
35 |
+
is_immutable(self)
|
36 |
+
|
37 |
+
def __imul__(self, other):
|
38 |
+
is_immutable(self)
|
39 |
+
|
40 |
+
def __setitem__(self, key, value):
|
41 |
+
is_immutable(self)
|
42 |
+
|
43 |
+
def append(self, item):
|
44 |
+
is_immutable(self)
|
45 |
+
|
46 |
+
def remove(self, item):
|
47 |
+
is_immutable(self)
|
48 |
+
|
49 |
+
def extend(self, iterable):
|
50 |
+
is_immutable(self)
|
51 |
+
|
52 |
+
def insert(self, pos, value):
|
53 |
+
is_immutable(self)
|
54 |
+
|
55 |
+
def pop(self, index=-1):
|
56 |
+
is_immutable(self)
|
57 |
+
|
58 |
+
def reverse(self):
|
59 |
+
is_immutable(self)
|
60 |
+
|
61 |
+
def sort(self, key=None, reverse=False):
|
62 |
+
is_immutable(self)
|
63 |
+
|
64 |
+
|
65 |
+
class ImmutableDictMixin:
|
66 |
+
"""Makes a :class:`dict` immutable.
|
67 |
+
|
68 |
+
.. versionadded:: 0.5
|
69 |
+
|
70 |
+
:private:
|
71 |
+
"""
|
72 |
+
|
73 |
+
_hash_cache = None
|
74 |
+
|
75 |
+
@classmethod
|
76 |
+
def fromkeys(cls, keys, value=None):
|
77 |
+
instance = super().__new__(cls)
|
78 |
+
instance.__init__(zip(keys, repeat(value)))
|
79 |
+
return instance
|
80 |
+
|
81 |
+
def __reduce_ex__(self, protocol):
|
82 |
+
return type(self), (dict(self),)
|
83 |
+
|
84 |
+
def _iter_hashitems(self):
|
85 |
+
return self.items()
|
86 |
+
|
87 |
+
def __hash__(self):
|
88 |
+
if self._hash_cache is not None:
|
89 |
+
return self._hash_cache
|
90 |
+
rv = self._hash_cache = hash(frozenset(self._iter_hashitems()))
|
91 |
+
return rv
|
92 |
+
|
93 |
+
def setdefault(self, key, default=None):
|
94 |
+
is_immutable(self)
|
95 |
+
|
96 |
+
def update(self, *args, **kwargs):
|
97 |
+
is_immutable(self)
|
98 |
+
|
99 |
+
def pop(self, key, default=None):
|
100 |
+
is_immutable(self)
|
101 |
+
|
102 |
+
def popitem(self):
|
103 |
+
is_immutable(self)
|
104 |
+
|
105 |
+
def __setitem__(self, key, value):
|
106 |
+
is_immutable(self)
|
107 |
+
|
108 |
+
def __delitem__(self, key):
|
109 |
+
is_immutable(self)
|
110 |
+
|
111 |
+
def clear(self):
|
112 |
+
is_immutable(self)
|
113 |
+
|
114 |
+
|
115 |
+
class ImmutableMultiDictMixin(ImmutableDictMixin):
|
116 |
+
"""Makes a :class:`MultiDict` immutable.
|
117 |
+
|
118 |
+
.. versionadded:: 0.5
|
119 |
+
|
120 |
+
:private:
|
121 |
+
"""
|
122 |
+
|
123 |
+
def __reduce_ex__(self, protocol):
|
124 |
+
return type(self), (list(self.items(multi=True)),)
|
125 |
+
|
126 |
+
def _iter_hashitems(self):
|
127 |
+
return self.items(multi=True)
|
128 |
+
|
129 |
+
def add(self, key, value):
|
130 |
+
is_immutable(self)
|
131 |
+
|
132 |
+
def popitemlist(self):
|
133 |
+
is_immutable(self)
|
134 |
+
|
135 |
+
def poplist(self, key):
|
136 |
+
is_immutable(self)
|
137 |
+
|
138 |
+
def setlist(self, key, new_list):
|
139 |
+
is_immutable(self)
|
140 |
+
|
141 |
+
def setlistdefault(self, key, default_list=None):
|
142 |
+
is_immutable(self)
|
143 |
+
|
144 |
+
|
145 |
+
class ImmutableHeadersMixin:
|
146 |
+
"""Makes a :class:`Headers` immutable. We do not mark them as
|
147 |
+
hashable though since the only usecase for this datastructure
|
148 |
+
in Werkzeug is a view on a mutable structure.
|
149 |
+
|
150 |
+
.. versionadded:: 0.5
|
151 |
+
|
152 |
+
:private:
|
153 |
+
"""
|
154 |
+
|
155 |
+
def __delitem__(self, key, **kwargs):
|
156 |
+
is_immutable(self)
|
157 |
+
|
158 |
+
def __setitem__(self, key, value):
|
159 |
+
is_immutable(self)
|
160 |
+
|
161 |
+
def set(self, _key, _value, **kwargs):
|
162 |
+
is_immutable(self)
|
163 |
+
|
164 |
+
def setlist(self, key, values):
|
165 |
+
is_immutable(self)
|
166 |
+
|
167 |
+
def add(self, _key, _value, **kwargs):
|
168 |
+
is_immutable(self)
|
169 |
+
|
170 |
+
def add_header(self, _key, _value, **_kwargs):
|
171 |
+
is_immutable(self)
|
172 |
+
|
173 |
+
def remove(self, key):
|
174 |
+
is_immutable(self)
|
175 |
+
|
176 |
+
def extend(self, *args, **kwargs):
|
177 |
+
is_immutable(self)
|
178 |
+
|
179 |
+
def update(self, *args, **kwargs):
|
180 |
+
is_immutable(self)
|
181 |
+
|
182 |
+
def insert(self, pos, value):
|
183 |
+
is_immutable(self)
|
184 |
+
|
185 |
+
def pop(self, key=None, default=_missing):
|
186 |
+
is_immutable(self)
|
187 |
+
|
188 |
+
def popitem(self):
|
189 |
+
is_immutable(self)
|
190 |
+
|
191 |
+
def setdefault(self, key, default):
|
192 |
+
is_immutable(self)
|
193 |
+
|
194 |
+
def setlistdefault(self, key, default):
|
195 |
+
is_immutable(self)
|
196 |
+
|
197 |
+
|
198 |
+
def _calls_update(name):
|
199 |
+
def oncall(self, *args, **kw):
|
200 |
+
rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw)
|
201 |
+
|
202 |
+
if self.on_update is not None:
|
203 |
+
self.on_update(self)
|
204 |
+
|
205 |
+
return rv
|
206 |
+
|
207 |
+
oncall.__name__ = name
|
208 |
+
return oncall
|
209 |
+
|
210 |
+
|
211 |
+
class UpdateDictMixin(dict):
|
212 |
+
"""Makes dicts call `self.on_update` on modifications.
|
213 |
+
|
214 |
+
.. versionadded:: 0.5
|
215 |
+
|
216 |
+
:private:
|
217 |
+
"""
|
218 |
+
|
219 |
+
on_update = None
|
220 |
+
|
221 |
+
def setdefault(self, key, default=None):
|
222 |
+
modified = key not in self
|
223 |
+
rv = super().setdefault(key, default)
|
224 |
+
if modified and self.on_update is not None:
|
225 |
+
self.on_update(self)
|
226 |
+
return rv
|
227 |
+
|
228 |
+
def pop(self, key, default=_missing):
|
229 |
+
modified = key in self
|
230 |
+
if default is _missing:
|
231 |
+
rv = super().pop(key)
|
232 |
+
else:
|
233 |
+
rv = super().pop(key, default)
|
234 |
+
if modified and self.on_update is not None:
|
235 |
+
self.on_update(self)
|
236 |
+
return rv
|
237 |
+
|
238 |
+
__setitem__ = _calls_update("__setitem__")
|
239 |
+
__delitem__ = _calls_update("__delitem__")
|
240 |
+
clear = _calls_update("clear")
|
241 |
+
popitem = _calls_update("popitem")
|
242 |
+
update = _calls_update("update")
|
MLPY/Lib/site-packages/werkzeug/datastructures/mixins.pyi
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections.abc import Callable
|
2 |
+
from collections.abc import Hashable
|
3 |
+
from collections.abc import Iterable
|
4 |
+
from typing import Any
|
5 |
+
from typing import NoReturn
|
6 |
+
from typing import overload
|
7 |
+
from typing import SupportsIndex
|
8 |
+
from typing import TypeVar
|
9 |
+
|
10 |
+
from _typeshed import SupportsKeysAndGetItem
|
11 |
+
|
12 |
+
from .headers import Headers
|
13 |
+
|
14 |
+
K = TypeVar("K")
|
15 |
+
T = TypeVar("T")
|
16 |
+
V = TypeVar("V")
|
17 |
+
|
18 |
+
def is_immutable(self: object) -> NoReturn: ...
|
19 |
+
|
20 |
+
class ImmutableListMixin(list[V]):
|
21 |
+
_hash_cache: int | None
|
22 |
+
def __hash__(self) -> int: ... # type: ignore
|
23 |
+
def __delitem__(self, key: SupportsIndex | slice) -> NoReturn: ...
|
24 |
+
def __iadd__(self, other: Any) -> NoReturn: ... # type: ignore
|
25 |
+
def __imul__(self, other: SupportsIndex) -> NoReturn: ...
|
26 |
+
def __setitem__(self, key: int | slice, value: V) -> NoReturn: ... # type: ignore
|
27 |
+
def append(self, value: V) -> NoReturn: ...
|
28 |
+
def remove(self, value: V) -> NoReturn: ...
|
29 |
+
def extend(self, values: Iterable[V]) -> NoReturn: ...
|
30 |
+
def insert(self, pos: SupportsIndex, value: V) -> NoReturn: ...
|
31 |
+
def pop(self, index: SupportsIndex = -1) -> NoReturn: ...
|
32 |
+
def reverse(self) -> NoReturn: ...
|
33 |
+
def sort(
|
34 |
+
self, key: Callable[[V], Any] | None = None, reverse: bool = False
|
35 |
+
) -> NoReturn: ...
|
36 |
+
|
37 |
+
class ImmutableDictMixin(dict[K, V]):
|
38 |
+
_hash_cache: int | None
|
39 |
+
@classmethod
|
40 |
+
def fromkeys( # type: ignore
|
41 |
+
cls, keys: Iterable[K], value: V | None = None
|
42 |
+
) -> ImmutableDictMixin[K, V]: ...
|
43 |
+
def _iter_hashitems(self) -> Iterable[Hashable]: ...
|
44 |
+
def __hash__(self) -> int: ... # type: ignore
|
45 |
+
def setdefault(self, key: K, default: V | None = None) -> NoReturn: ...
|
46 |
+
def update(self, *args: Any, **kwargs: V) -> NoReturn: ...
|
47 |
+
def pop(self, key: K, default: V | None = None) -> NoReturn: ... # type: ignore
|
48 |
+
def popitem(self) -> NoReturn: ...
|
49 |
+
def __setitem__(self, key: K, value: V) -> NoReturn: ...
|
50 |
+
def __delitem__(self, key: K) -> NoReturn: ...
|
51 |
+
def clear(self) -> NoReturn: ...
|
52 |
+
|
53 |
+
class ImmutableMultiDictMixin(ImmutableDictMixin[K, V]):
|
54 |
+
def _iter_hashitems(self) -> Iterable[Hashable]: ...
|
55 |
+
def add(self, key: K, value: V) -> NoReturn: ...
|
56 |
+
def popitemlist(self) -> NoReturn: ...
|
57 |
+
def poplist(self, key: K) -> NoReturn: ...
|
58 |
+
def setlist(self, key: K, new_list: Iterable[V]) -> NoReturn: ...
|
59 |
+
def setlistdefault(
|
60 |
+
self, key: K, default_list: Iterable[V] | None = None
|
61 |
+
) -> NoReturn: ...
|
62 |
+
|
63 |
+
class ImmutableHeadersMixin(Headers):
|
64 |
+
def __delitem__(self, key: Any, _index_operation: bool = True) -> NoReturn: ...
|
65 |
+
def __setitem__(self, key: Any, value: Any) -> NoReturn: ...
|
66 |
+
def set(self, _key: Any, _value: Any, **kw: Any) -> NoReturn: ...
|
67 |
+
def setlist(self, key: Any, values: Any) -> NoReturn: ...
|
68 |
+
def add(self, _key: Any, _value: Any, **kw: Any) -> NoReturn: ...
|
69 |
+
def add_header(self, _key: Any, _value: Any, **_kw: Any) -> NoReturn: ...
|
70 |
+
def remove(self, key: Any) -> NoReturn: ...
|
71 |
+
def extend(self, *args: Any, **kwargs: Any) -> NoReturn: ...
|
72 |
+
def update(self, *args: Any, **kwargs: Any) -> NoReturn: ...
|
73 |
+
def insert(self, pos: Any, value: Any) -> NoReturn: ...
|
74 |
+
def pop(self, key: Any = None, default: Any = ...) -> NoReturn: ...
|
75 |
+
def popitem(self) -> NoReturn: ...
|
76 |
+
def setdefault(self, key: Any, default: Any) -> NoReturn: ...
|
77 |
+
def setlistdefault(self, key: Any, default: Any) -> NoReturn: ...
|
78 |
+
|
79 |
+
def _calls_update(name: str) -> Callable[[UpdateDictMixin[K, V]], Any]: ...
|
80 |
+
|
81 |
+
class UpdateDictMixin(dict[K, V]):
|
82 |
+
on_update: Callable[[UpdateDictMixin[K, V] | None, None], None]
|
83 |
+
def setdefault(self, key: K, default: V | None = None) -> V: ...
|
84 |
+
@overload
|
85 |
+
def pop(self, key: K) -> V: ...
|
86 |
+
@overload
|
87 |
+
def pop(self, key: K, default: V | T = ...) -> V | T: ...
|
88 |
+
def __setitem__(self, key: K, value: V) -> None: ...
|
89 |
+
def __delitem__(self, key: K) -> None: ...
|
90 |
+
def clear(self) -> None: ...
|
91 |
+
def popitem(self) -> tuple[K, V]: ...
|
92 |
+
@overload
|
93 |
+
def update(self, __m: SupportsKeysAndGetItem[K, V], **kwargs: V) -> None: ...
|
94 |
+
@overload
|
95 |
+
def update(self, __m: Iterable[tuple[K, V]], **kwargs: V) -> None: ...
|
96 |
+
@overload
|
97 |
+
def update(self, **kwargs: V) -> None: ...
|