ZhengyangZhang commited on
Commit
c4a2245
·
verified ·
1 Parent(s): 4dfcf95

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/_distutils_hack/__init__.py +239 -0
  2. lib/python3.12/site-packages/_distutils_hack/__pycache__/__init__.cpython-312.pyc +0 -0
  3. lib/python3.12/site-packages/_distutils_hack/__pycache__/override.cpython-312.pyc +0 -0
  4. lib/python3.12/site-packages/_distutils_hack/override.py +1 -0
  5. lib/python3.12/site-packages/dill-0.3.8.dist-info/INSTALLER +1 -0
  6. lib/python3.12/site-packages/dill-0.3.8.dist-info/LICENSE +35 -0
  7. lib/python3.12/site-packages/dill-0.3.8.dist-info/METADATA +280 -0
  8. lib/python3.12/site-packages/dill-0.3.8.dist-info/RECORD +97 -0
  9. lib/python3.12/site-packages/dill-0.3.8.dist-info/WHEEL +5 -0
  10. lib/python3.12/site-packages/dill-0.3.8.dist-info/top_level.txt +1 -0
  11. lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/INSTALLER +1 -0
  12. lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/METADATA +278 -0
  13. lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/RECORD +115 -0
  14. lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/WHEEL +4 -0
  15. lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/licenses/LICENSE +29 -0
  16. lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/INSTALLER +1 -0
  17. lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/LICENSE +30 -0
  18. lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/METADATA +26 -0
  19. lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/RECORD +8 -0
  20. lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/WHEEL +4 -0
  21. lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/entry_points.txt +5 -0
  22. lib/python3.12/site-packages/jinja2/__init__.py +38 -0
  23. lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc +0 -0
  24. lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc +0 -0
  25. lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc +0 -0
  28. lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc +0 -0
  29. lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc +0 -0
  30. lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc +0 -0
  31. lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc +0 -0
  32. lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc +0 -0
  33. lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc +0 -0
  34. lib/python3.12/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc +0 -0
  35. lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc +0 -0
  36. lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc +0 -0
  37. lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc +0 -0
  38. lib/python3.12/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc +0 -0
  39. lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc +0 -0
  40. lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc +0 -0
  41. lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc +0 -0
  44. lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc +0 -0
  45. lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc +0 -0
  47. lib/python3.12/site-packages/jinja2/_identifier.py +6 -0
  48. lib/python3.12/site-packages/jinja2/async_utils.py +99 -0
  49. lib/python3.12/site-packages/jinja2/bccache.py +408 -0
  50. lib/python3.12/site-packages/jinja2/compiler.py +1998 -0
lib/python3.12/site-packages/_distutils_hack/__init__.py ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # don't import any costly modules
2
+ import os
3
+ import sys
4
+
5
+ report_url = (
6
+ "https://github.com/pypa/setuptools/issues/new?template=distutils-deprecation.yml"
7
+ )
8
+
9
+
10
+ def warn_distutils_present():
11
+ if 'distutils' not in sys.modules:
12
+ return
13
+ import warnings
14
+
15
+ warnings.warn(
16
+ "Distutils was imported before Setuptools, but importing Setuptools "
17
+ "also replaces the `distutils` module in `sys.modules`. This may lead "
18
+ "to undesirable behaviors or errors. To avoid these issues, avoid "
19
+ "using distutils directly, ensure that setuptools is installed in the "
20
+ "traditional way (e.g. not an editable install), and/or make sure "
21
+ "that setuptools is always imported before distutils."
22
+ )
23
+
24
+
25
+ def clear_distutils():
26
+ if 'distutils' not in sys.modules:
27
+ return
28
+ import warnings
29
+
30
+ warnings.warn(
31
+ "Setuptools is replacing distutils. Support for replacing "
32
+ "an already imported distutils is deprecated. In the future, "
33
+ "this condition will fail. "
34
+ f"Register concerns at {report_url}"
35
+ )
36
+ mods = [
37
+ name
38
+ for name in sys.modules
39
+ if name == "distutils" or name.startswith("distutils.")
40
+ ]
41
+ for name in mods:
42
+ del sys.modules[name]
43
+
44
+
45
+ def enabled():
46
+ """
47
+ Allow selection of distutils by environment variable.
48
+ """
49
+ which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local')
50
+ if which == 'stdlib':
51
+ import warnings
52
+
53
+ warnings.warn(
54
+ "Reliance on distutils from stdlib is deprecated. Users "
55
+ "must rely on setuptools to provide the distutils module. "
56
+ "Avoid importing distutils or import setuptools first, "
57
+ "and avoid setting SETUPTOOLS_USE_DISTUTILS=stdlib. "
58
+ f"Register concerns at {report_url}"
59
+ )
60
+ return which == 'local'
61
+
62
+
63
+ def ensure_local_distutils():
64
+ import importlib
65
+
66
+ clear_distutils()
67
+
68
+ # With the DistutilsMetaFinder in place,
69
+ # perform an import to cause distutils to be
70
+ # loaded from setuptools._distutils. Ref #2906.
71
+ with shim():
72
+ importlib.import_module('distutils')
73
+
74
+ # check that submodules load as expected
75
+ core = importlib.import_module('distutils.core')
76
+ assert '_distutils' in core.__file__, core.__file__
77
+ assert 'setuptools._distutils.log' not in sys.modules
78
+
79
+
80
+ def do_override():
81
+ """
82
+ Ensure that the local copy of distutils is preferred over stdlib.
83
+
84
+ See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
85
+ for more motivation.
86
+ """
87
+ if enabled():
88
+ warn_distutils_present()
89
+ ensure_local_distutils()
90
+
91
+
92
+ class _TrivialRe:
93
+ def __init__(self, *patterns) -> None:
94
+ self._patterns = patterns
95
+
96
+ def match(self, string):
97
+ return all(pat in string for pat in self._patterns)
98
+
99
+
100
+ class DistutilsMetaFinder:
101
+ def find_spec(self, fullname, path, target=None):
102
+ # optimization: only consider top level modules and those
103
+ # found in the CPython test suite.
104
+ if path is not None and not fullname.startswith('test.'):
105
+ return None
106
+
107
+ method_name = 'spec_for_{fullname}'.format(**locals())
108
+ method = getattr(self, method_name, lambda: None)
109
+ return method()
110
+
111
+ def spec_for_distutils(self):
112
+ if self.is_cpython():
113
+ return None
114
+
115
+ import importlib
116
+ import importlib.abc
117
+ import importlib.util
118
+
119
+ try:
120
+ mod = importlib.import_module('setuptools._distutils')
121
+ except Exception:
122
+ # There are a couple of cases where setuptools._distutils
123
+ # may not be present:
124
+ # - An older Setuptools without a local distutils is
125
+ # taking precedence. Ref #2957.
126
+ # - Path manipulation during sitecustomize removes
127
+ # setuptools from the path but only after the hook
128
+ # has been loaded. Ref #2980.
129
+ # In either case, fall back to stdlib behavior.
130
+ return None
131
+
132
+ class DistutilsLoader(importlib.abc.Loader):
133
+ def create_module(self, spec):
134
+ mod.__name__ = 'distutils'
135
+ return mod
136
+
137
+ def exec_module(self, module):
138
+ pass
139
+
140
+ return importlib.util.spec_from_loader(
141
+ 'distutils', DistutilsLoader(), origin=mod.__file__
142
+ )
143
+
144
+ @staticmethod
145
+ def is_cpython():
146
+ """
147
+ Suppress supplying distutils for CPython (build and tests).
148
+ Ref #2965 and #3007.
149
+ """
150
+ return os.path.isfile('pybuilddir.txt')
151
+
152
+ def spec_for_pip(self):
153
+ """
154
+ Ensure stdlib distutils when running under pip.
155
+ See pypa/pip#8761 for rationale.
156
+ """
157
+ if sys.version_info >= (3, 12) or self.pip_imported_during_build():
158
+ return
159
+ clear_distutils()
160
+ self.spec_for_distutils = lambda: None
161
+
162
+ @classmethod
163
+ def pip_imported_during_build(cls):
164
+ """
165
+ Detect if pip is being imported in a build script. Ref #2355.
166
+ """
167
+ import traceback
168
+
169
+ return any(
170
+ cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None)
171
+ )
172
+
173
+ @staticmethod
174
+ def frame_file_is_setup(frame):
175
+ """
176
+ Return True if the indicated frame suggests a setup.py file.
177
+ """
178
+ # some frames may not have __file__ (#2940)
179
+ return frame.f_globals.get('__file__', '').endswith('setup.py')
180
+
181
+ def spec_for_sensitive_tests(self):
182
+ """
183
+ Ensure stdlib distutils when running select tests under CPython.
184
+
185
+ python/cpython#91169
186
+ """
187
+ clear_distutils()
188
+ self.spec_for_distutils = lambda: None
189
+
190
+ sensitive_tests = (
191
+ [
192
+ 'test.test_distutils',
193
+ 'test.test_peg_generator',
194
+ 'test.test_importlib',
195
+ ]
196
+ if sys.version_info < (3, 10)
197
+ else [
198
+ 'test.test_distutils',
199
+ ]
200
+ )
201
+
202
+
203
+ for name in DistutilsMetaFinder.sensitive_tests:
204
+ setattr(
205
+ DistutilsMetaFinder,
206
+ f'spec_for_{name}',
207
+ DistutilsMetaFinder.spec_for_sensitive_tests,
208
+ )
209
+
210
+
211
+ DISTUTILS_FINDER = DistutilsMetaFinder()
212
+
213
+
214
+ def add_shim():
215
+ DISTUTILS_FINDER in sys.meta_path or insert_shim()
216
+
217
+
218
+ class shim:
219
+ def __enter__(self) -> None:
220
+ insert_shim()
221
+
222
+ def __exit__(self, exc: object, value: object, tb: object) -> None:
223
+ _remove_shim()
224
+
225
+
226
+ def insert_shim():
227
+ sys.meta_path.insert(0, DISTUTILS_FINDER)
228
+
229
+
230
+ def _remove_shim():
231
+ try:
232
+ sys.meta_path.remove(DISTUTILS_FINDER)
233
+ except ValueError:
234
+ pass
235
+
236
+
237
+ if sys.version_info < (3, 12):
238
+ # DistutilsMetaFinder can only be disabled in Python < 3.12 (PEP 632)
239
+ remove_shim = _remove_shim
lib/python3.12/site-packages/_distutils_hack/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (10.6 kB). View file
 
lib/python3.12/site-packages/_distutils_hack/__pycache__/override.cpython-312.pyc ADDED
Binary file (295 Bytes). View file
 
lib/python3.12/site-packages/_distutils_hack/override.py ADDED
@@ -0,0 +1 @@
 
 
1
+ __import__('_distutils_hack').do_override()
lib/python3.12/site-packages/dill-0.3.8.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
lib/python3.12/site-packages/dill-0.3.8.dist-info/LICENSE ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2004-2016 California Institute of Technology.
2
+ Copyright (c) 2016-2024 The Uncertainty Quantification Foundation.
3
+ All rights reserved.
4
+
5
+ This software is available subject to the conditions and terms laid
6
+ out below. By downloading and using this software you are agreeing
7
+ to the following conditions.
8
+
9
+ Redistribution and use in source and binary forms, with or without
10
+ modification, are permitted provided that the following conditions
11
+ are met:
12
+
13
+ - Redistributions of source code must retain the above copyright
14
+ notice, this list of conditions and the following disclaimer.
15
+
16
+ - Redistributions in binary form must reproduce the above copyright
17
+ notice, this list of conditions and the following disclaimer in the
18
+ documentation and/or other materials provided with the distribution.
19
+
20
+ - Neither the names of the copyright holders nor the names of any of
21
+ the contributors may be used to endorse or promote products derived
22
+ from this software without specific prior written permission.
23
+
24
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+
lib/python3.12/site-packages/dill-0.3.8.dist-info/METADATA ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: dill
3
+ Version: 0.3.8
4
+ Summary: serialize all of Python
5
+ Home-page: https://github.com/uqfoundation/dill
6
+ Author: Mike McKerns
7
+ Author-email: mmckerns@uqfoundation.org
8
+ Maintainer: Mike McKerns
9
+ Maintainer-email: mmckerns@uqfoundation.org
10
+ License: BSD-3-Clause
11
+ Download-URL: https://pypi.org/project/dill/#files
12
+ Project-URL: Documentation, http://dill.rtfd.io
13
+ Project-URL: Source Code, https://github.com/uqfoundation/dill
14
+ Project-URL: Bug Tracker, https://github.com/uqfoundation/dill/issues
15
+ Platform: Linux
16
+ Platform: Windows
17
+ Platform: Mac
18
+ Classifier: Development Status :: 5 - Production/Stable
19
+ Classifier: Intended Audience :: Developers
20
+ Classifier: Intended Audience :: Science/Research
21
+ Classifier: License :: OSI Approved :: BSD License
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.8
24
+ Classifier: Programming Language :: Python :: 3.9
25
+ Classifier: Programming Language :: Python :: 3.10
26
+ Classifier: Programming Language :: Python :: 3.11
27
+ Classifier: Programming Language :: Python :: 3.12
28
+ Classifier: Programming Language :: Python :: Implementation :: CPython
29
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
30
+ Classifier: Topic :: Scientific/Engineering
31
+ Classifier: Topic :: Software Development
32
+ Requires-Python: >=3.8
33
+ Provides-Extra: graph
34
+ Requires-Dist: objgraph (>=1.7.2) ; extra == 'graph'
35
+ Provides-Extra: profile
36
+ Requires-Dist: gprof2dot (>=2022.7.29) ; extra == 'profile'
37
+ Provides-Extra: readline
38
+
39
+ -----------------------------
40
+ dill: serialize all of Python
41
+ -----------------------------
42
+
43
+ About Dill
44
+ ==========
45
+
46
+ ``dill`` extends Python's ``pickle`` module for serializing and de-serializing
47
+ Python objects to the majority of the built-in Python types. Serialization
48
+ is the process of converting an object to a byte stream, and the inverse
49
+ of which is converting a byte stream back to a Python object hierarchy.
50
+
51
+ ``dill`` provides the user the same interface as the ``pickle`` module, and
52
+ also includes some additional features. In addition to pickling Python
53
+ objects, ``dill`` provides the ability to save the state of an interpreter
54
+ session in a single command. Hence, it would be feasible to save an
55
+ interpreter session, close the interpreter, ship the pickled file to
56
+ another computer, open a new interpreter, unpickle the session and
57
+ thus continue from the 'saved' state of the original interpreter
58
+ session.
59
+
60
+ ``dill`` can be used to store Python objects to a file, but the primary
61
+ usage is to send Python objects across the network as a byte stream.
62
+ ``dill`` is quite flexible, and allows arbitrary user defined classes
63
+ and functions to be serialized. Thus ``dill`` is not intended to be
64
+ secure against erroneously or maliciously constructed data. It is
65
+ left to the user to decide whether the data they unpickle is from
66
+ a trustworthy source.
67
+
68
+ ``dill`` is part of ``pathos``, a Python framework for heterogeneous computing.
69
+ ``dill`` is in active development, so any user feedback, bug reports, comments,
70
+ or suggestions are highly appreciated. A list of issues is located at
71
+ https://github.com/uqfoundation/dill/issues, with a legacy list maintained at
72
+ https://uqfoundation.github.io/project/pathos/query.
73
+
74
+
75
+ Major Features
76
+ ==============
77
+
78
+ ``dill`` can pickle the following standard types:
79
+
80
+ - none, type, bool, int, float, complex, bytes, str,
81
+ - tuple, list, dict, file, buffer, builtin,
82
+ - Python classes, namedtuples, dataclasses, metaclasses,
83
+ - instances of classes,
84
+ - set, frozenset, array, functions, exceptions
85
+
86
+ ``dill`` can also pickle more 'exotic' standard types:
87
+
88
+ - functions with yields, nested functions, lambdas,
89
+ - cell, method, unboundmethod, module, code, methodwrapper,
90
+ - methoddescriptor, getsetdescriptor, memberdescriptor, wrapperdescriptor,
91
+ - dictproxy, slice, notimplemented, ellipsis, quit
92
+
93
+ ``dill`` cannot yet pickle these standard types:
94
+
95
+ - frame, generator, traceback
96
+
97
+ ``dill`` also provides the capability to:
98
+
99
+ - save and load Python interpreter sessions
100
+ - save and extract the source code from functions and classes
101
+ - interactively diagnose pickling errors
102
+
103
+
104
+ Current Release
105
+ ===============
106
+
107
+ The latest released version of ``dill`` is available from:
108
+
109
+ https://pypi.org/project/dill
110
+
111
+ ``dill`` is distributed under a 3-clause BSD license.
112
+
113
+
114
+ Development Version
115
+ ===================
116
+
117
+ You can get the latest development version with all the shiny new features at:
118
+
119
+ https://github.com/uqfoundation
120
+
121
+ If you have a new contribution, please submit a pull request.
122
+
123
+
124
+ Installation
125
+ ============
126
+
127
+ ``dill`` can be installed with ``pip``::
128
+
129
+ $ pip install dill
130
+
131
+ To optionally include the ``objgraph`` diagnostic tool in the install::
132
+
133
+ $ pip install dill[graph]
134
+
135
+ To optionally include the ``gprof2dot`` diagnostic tool in the install::
136
+
137
+ $ pip install dill[profile]
138
+
139
+ For windows users, to optionally install session history tools::
140
+
141
+ $ pip install dill[readline]
142
+
143
+
144
+ Requirements
145
+ ============
146
+
147
+ ``dill`` requires:
148
+
149
+ - ``python`` (or ``pypy``), **>=3.8**
150
+ - ``setuptools``, **>=42**
151
+
152
+ Optional requirements:
153
+
154
+ - ``objgraph``, **>=1.7.2**
155
+ - ``gprof2dot``, **>=2022.7.29**
156
+ - ``pyreadline``, **>=1.7.1** (on windows)
157
+
158
+
159
+ Basic Usage
160
+ ===========
161
+
162
+ ``dill`` is a drop-in replacement for ``pickle``. Existing code can be
163
+ updated to allow complete pickling using::
164
+
165
+ >>> import dill as pickle
166
+
167
+ or::
168
+
169
+ >>> from dill import dumps, loads
170
+
171
+ ``dumps`` converts the object to a unique byte string, and ``loads`` performs
172
+ the inverse operation::
173
+
174
+ >>> squared = lambda x: x**2
175
+ >>> loads(dumps(squared))(3)
176
+ 9
177
+
178
+ There are a number of options to control serialization which are provided
179
+ as keyword arguments to several ``dill`` functions:
180
+
181
+ * with *protocol*, the pickle protocol level can be set. This uses the
182
+ same value as the ``pickle`` module, *DEFAULT_PROTOCOL*.
183
+ * with *byref=True*, ``dill`` to behave a lot more like pickle with
184
+ certain objects (like modules) pickled by reference as opposed to
185
+ attempting to pickle the object itself.
186
+ * with *recurse=True*, objects referred to in the global dictionary are
187
+ recursively traced and pickled, instead of the default behavior of
188
+ attempting to store the entire global dictionary.
189
+ * with *fmode*, the contents of the file can be pickled along with the file
190
+ handle, which is useful if the object is being sent over the wire to a
191
+ remote system which does not have the original file on disk. Options are
192
+ *HANDLE_FMODE* for just the handle, *CONTENTS_FMODE* for the file content
193
+ and *FILE_FMODE* for content and handle.
194
+ * with *ignore=False*, objects reconstructed with types defined in the
195
+ top-level script environment use the existing type in the environment
196
+ rather than a possibly different reconstructed type.
197
+
198
+ The default serialization can also be set globally in *dill.settings*.
199
+ Thus, we can modify how ``dill`` handles references to the global dictionary
200
+ locally or globally::
201
+
202
+ >>> import dill.settings
203
+ >>> dumps(absolute) == dumps(absolute, recurse=True)
204
+ False
205
+ >>> dill.settings['recurse'] = True
206
+ >>> dumps(absolute) == dumps(absolute, recurse=True)
207
+ True
208
+
209
+ ``dill`` also includes source code inspection, as an alternate to pickling::
210
+
211
+ >>> import dill.source
212
+ >>> print(dill.source.getsource(squared))
213
+ squared = lambda x:x**2
214
+
215
+ To aid in debugging pickling issues, use *dill.detect* which provides
216
+ tools like pickle tracing::
217
+
218
+ >>> import dill.detect
219
+ >>> with dill.detect.trace():
220
+ >>> dumps(squared)
221
+ ┬ F1: <function <lambda> at 0x7fe074f8c280>
222
+ ├┬ F2: <function _create_function at 0x7fe074c49c10>
223
+ │└ # F2 [34 B]
224
+ ├┬ Co: <code object <lambda> at 0x7fe07501eb30, file "<stdin>", line 1>
225
+ │├┬ F2: <function _create_code at 0x7fe074c49ca0>
226
+ ││└ # F2 [19 B]
227
+ │└ # Co [87 B]
228
+ ├┬ D1: <dict object at 0x7fe0750d4680>
229
+ │└ # D1 [22 B]
230
+ ├┬ D2: <dict object at 0x7fe074c5a1c0>
231
+ │└ # D2 [2 B]
232
+ ├┬ D2: <dict object at 0x7fe074f903c0>
233
+ │├┬ D2: <dict object at 0x7fe074f8ebc0>
234
+ ││└ # D2 [2 B]
235
+ │└ # D2 [23 B]
236
+ └ # F1 [180 B]
237
+
238
+ With trace, we see how ``dill`` stored the lambda (``F1``) by first storing
239
+ ``_create_function``, the underlying code object (``Co``) and ``_create_code``
240
+ (which is used to handle code objects), then we handle the reference to
241
+ the global dict (``D2``) plus other dictionaries (``D1`` and ``D2``) that
242
+ save the lambda object's state. A ``#`` marks when the object is actually stored.
243
+
244
+
245
+ More Information
246
+ ================
247
+
248
+ Probably the best way to get started is to look at the documentation at
249
+ http://dill.rtfd.io. Also see ``dill.tests`` for a set of scripts that
250
+ demonstrate how ``dill`` can serialize different Python objects. You can
251
+ run the test suite with ``python -m dill.tests``. The contents of any
252
+ pickle file can be examined with ``undill``. As ``dill`` conforms to
253
+ the ``pickle`` interface, the examples and documentation found at
254
+ http://docs.python.org/library/pickle.html also apply to ``dill``
255
+ if one will ``import dill as pickle``. The source code is also generally
256
+ well documented, so further questions may be resolved by inspecting the
257
+ code itself. Please feel free to submit a ticket on github, or ask a
258
+ question on stackoverflow (**@Mike McKerns**).
259
+ If you would like to share how you use ``dill`` in your work, please send
260
+ an email (to **mmckerns at uqfoundation dot org**).
261
+
262
+
263
+ Citation
264
+ ========
265
+
266
+ If you use ``dill`` to do research that leads to publication, we ask that you
267
+ acknowledge use of ``dill`` by citing the following in your publication::
268
+
269
+ M.M. McKerns, L. Strand, T. Sullivan, A. Fang, M.A.G. Aivazis,
270
+ "Building a framework for predictive science", Proceedings of
271
+ the 10th Python in Science Conference, 2011;
272
+ http://arxiv.org/pdf/1202.1056
273
+
274
+ Michael McKerns and Michael Aivazis,
275
+ "pathos: a framework for heterogeneous computing", 2010- ;
276
+ https://uqfoundation.github.io/project/pathos
277
+
278
+ Please see https://uqfoundation.github.io/project/pathos or
279
+ http://arxiv.org/pdf/1202.1056 for further information.
280
+
lib/python3.12/site-packages/dill-0.3.8.dist-info/RECORD ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ../../../bin/get_gprof,sha256=jZwza08tDhPEpPkkixPInUBIcjGxLGfpL1ngSFppopQ,2493
2
+ ../../../bin/get_objgraph,sha256=BUf8yNZ_FCqN7E-ZzWvL1OtusOxMUpF1TtWcpiLaVSw,1687
3
+ ../../../bin/undill,sha256=G_121H3ieAfCeSH1t9AHd0AuZwHFNQZQ1v9bZiMeoPA,623
4
+ dill-0.3.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
5
+ dill-0.3.8.dist-info/LICENSE,sha256=UeiKI-eId86r1yfCGcel4z9l2pugOsT9KFupBKoc4is,1790
6
+ dill-0.3.8.dist-info/METADATA,sha256=UxkSs2cU8JyrJsV5kS0QR9crJ07hrUJS2RiIMQaC4ss,10106
7
+ dill-0.3.8.dist-info/RECORD,,
8
+ dill-0.3.8.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
9
+ dill-0.3.8.dist-info/top_level.txt,sha256=HLSIyYIjQzJiBvs3_-16ntezE3j6mWGTW0DT1xDd7X0,5
10
+ dill/__diff.py,sha256=kirMxzB7E8lfjo21M5oIf7if95ny0aWhYB790KMpN08,7143
11
+ dill/__info__.py,sha256=Kmel_yLTyH-hwNC5cVfzN-LV08AbS_AvSa2uwMeIQdk,10756
12
+ dill/__init__.py,sha256=j-Jxl3H6bxatS0h2f8ywWs7DChwk7B9ozuZQBVcjYGU,3798
13
+ dill/__pycache__/__diff.cpython-312.pyc,,
14
+ dill/__pycache__/__info__.cpython-312.pyc,,
15
+ dill/__pycache__/__init__.cpython-312.pyc,,
16
+ dill/__pycache__/_dill.cpython-312.pyc,,
17
+ dill/__pycache__/_objects.cpython-312.pyc,,
18
+ dill/__pycache__/_shims.cpython-312.pyc,,
19
+ dill/__pycache__/detect.cpython-312.pyc,,
20
+ dill/__pycache__/logger.cpython-312.pyc,,
21
+ dill/__pycache__/objtypes.cpython-312.pyc,,
22
+ dill/__pycache__/pointers.cpython-312.pyc,,
23
+ dill/__pycache__/session.cpython-312.pyc,,
24
+ dill/__pycache__/settings.cpython-312.pyc,,
25
+ dill/__pycache__/source.cpython-312.pyc,,
26
+ dill/__pycache__/temp.cpython-312.pyc,,
27
+ dill/_dill.py,sha256=3Eo6gKj1sODJjgPgYNT8TU-YL6QNQ7rIeWPUVnRzyqQ,88548
28
+ dill/_objects.py,sha256=dPlUXzQIh8CA0fMy9NMbwwLGUPmXe5H8MdQtRWB1b_M,19605
29
+ dill/_shims.py,sha256=IuzQcyPET5VWmWMoSGStieoedvNXlb5suDpa4bykTbQ,6635
30
+ dill/detect.py,sha256=Mb-PfCxn1mg0l3TmHXyPNVEc4n3fuxc_nue6eL3-q_o,11114
31
+ dill/logger.py,sha256=YS5ZloAOKjJRZaOBRCaMUDWmWVQZcicvbXVSrz8L8XU,11134
32
+ dill/objtypes.py,sha256=BamGH3BEM6lLlxisuvXcGjsCRLNeoLs4_rFZrM5r2yM,736
33
+ dill/pointers.py,sha256=vnQzjwGtKMGnmbdYRXRWNLMyceNPSw4f7UpvwCXLYbE,4467
34
+ dill/session.py,sha256=NvCWpoP9r_rGBL2pOwwxOri8mFly5KlIWG3GwkBFnc0,23525
35
+ dill/settings.py,sha256=7I3yvSpPKstOqpoW2gv3X77kXK-hZlqCnF7nJUGhxTY,630
36
+ dill/source.py,sha256=DWfIxcBjpjbbKYz2DstV9kRdjajBdZLOcLXfsZsPo9U,45121
37
+ dill/temp.py,sha256=KJUry4t0UjQCh5t4LXcxNyMF_uOGHwcjTuNYTJD9qdA,8027
38
+ dill/tests/__init__.py,sha256=Gx-chVB-l-e7ncsGp2zF4BimTjbUyO7BY7RkrO835vY,479
39
+ dill/tests/__main__.py,sha256=fHhioQwcOvTPlf1RM_wVQ0Y3ndETWJOuXJQ2rVtqliA,899
40
+ dill/tests/__pycache__/__init__.cpython-312.pyc,,
41
+ dill/tests/__pycache__/__main__.cpython-312.pyc,,
42
+ dill/tests/__pycache__/test_abc.cpython-312.pyc,,
43
+ dill/tests/__pycache__/test_check.cpython-312.pyc,,
44
+ dill/tests/__pycache__/test_classdef.cpython-312.pyc,,
45
+ dill/tests/__pycache__/test_dataclasses.cpython-312.pyc,,
46
+ dill/tests/__pycache__/test_detect.cpython-312.pyc,,
47
+ dill/tests/__pycache__/test_dictviews.cpython-312.pyc,,
48
+ dill/tests/__pycache__/test_diff.cpython-312.pyc,,
49
+ dill/tests/__pycache__/test_extendpickle.cpython-312.pyc,,
50
+ dill/tests/__pycache__/test_fglobals.cpython-312.pyc,,
51
+ dill/tests/__pycache__/test_file.cpython-312.pyc,,
52
+ dill/tests/__pycache__/test_functions.cpython-312.pyc,,
53
+ dill/tests/__pycache__/test_functors.cpython-312.pyc,,
54
+ dill/tests/__pycache__/test_logger.cpython-312.pyc,,
55
+ dill/tests/__pycache__/test_mixins.cpython-312.pyc,,
56
+ dill/tests/__pycache__/test_module.cpython-312.pyc,,
57
+ dill/tests/__pycache__/test_moduledict.cpython-312.pyc,,
58
+ dill/tests/__pycache__/test_nested.cpython-312.pyc,,
59
+ dill/tests/__pycache__/test_objects.cpython-312.pyc,,
60
+ dill/tests/__pycache__/test_properties.cpython-312.pyc,,
61
+ dill/tests/__pycache__/test_pycapsule.cpython-312.pyc,,
62
+ dill/tests/__pycache__/test_recursive.cpython-312.pyc,,
63
+ dill/tests/__pycache__/test_registered.cpython-312.pyc,,
64
+ dill/tests/__pycache__/test_restricted.cpython-312.pyc,,
65
+ dill/tests/__pycache__/test_selected.cpython-312.pyc,,
66
+ dill/tests/__pycache__/test_session.cpython-312.pyc,,
67
+ dill/tests/__pycache__/test_source.cpython-312.pyc,,
68
+ dill/tests/__pycache__/test_temp.cpython-312.pyc,,
69
+ dill/tests/__pycache__/test_weakref.cpython-312.pyc,,
70
+ dill/tests/test_abc.py,sha256=BSjSKKCQ5_iPfFxAd0yBq4KSAJxelrlC3IzoAhjd1C4,4227
71
+ dill/tests/test_check.py,sha256=4F5gkX6zxY7C5sD2_0Tkqf3T3jmQl0K15FOxYUTZQl0,1396
72
+ dill/tests/test_classdef.py,sha256=fI3fVk4SlsjNMMs5RfU6DUCaxpP7YYRjvLZ2nhXMHuc,8600
73
+ dill/tests/test_dataclasses.py,sha256=yKjFuG24ymLtjk-sZZdhvNY7aDqerTDpMcfi_eV4ft0,890
74
+ dill/tests/test_detect.py,sha256=sE9THufHXCDysBPQ4QkN5DHn6DaIldVRAEciseIRH08,4083
75
+ dill/tests/test_dictviews.py,sha256=Jhol0cQWPwoQrp7OPxGhU8FNRX2GgfFp9fTahCvQEPA,1337
76
+ dill/tests/test_diff.py,sha256=5VIWf2fpV6auLHNfzkHLTrgx6AJBlE2xe5Wanfmq8TM,2667
77
+ dill/tests/test_extendpickle.py,sha256=gONrMBHO94Edhnqm1wo49hgzwmaxHs7L-86Hs-7albY,1315
78
+ dill/tests/test_fglobals.py,sha256=DCvdojmKcLN_X9vX4Qe1FbsqjeoJK-wsY2uJwBfNFro,1676
79
+ dill/tests/test_file.py,sha256=jUU2h8qaDOIe1mn_Ng7wqCZcd7Ucx3TAaI-K_90_Tbk,13578
80
+ dill/tests/test_functions.py,sha256=-mqTpUbzRu8GynjBGD25dRDm8qInIe07sRZmCcA_iXY,4267
81
+ dill/tests/test_functors.py,sha256=7rx9wLmrgFwF0gUm_-SGOISPYSok0XjmrQ-jFMRt6gs,930
82
+ dill/tests/test_logger.py,sha256=D9zGRaA-CEadG13orPS_D4gPVZlkqXf9Zu8wn2oMiYc,2385
83
+ dill/tests/test_mixins.py,sha256=YtB24BjodooLj85ijFbAxiM7LlFQZAUL8RQVx9vIAwY,4007
84
+ dill/tests/test_module.py,sha256=KLl_gZJJqDY7S_bD5wCqKL8JQCS0MDMoipVQSDfASlo,1943
85
+ dill/tests/test_moduledict.py,sha256=faXG6-5AcmCfP3xe2FYGOUdSosU-9TWnKU_ZVqPDaxY,1182
86
+ dill/tests/test_nested.py,sha256=ViWiOrChLZktS0z6qyKqMxDdTuy9kAX4qMgH_OreMcc,3146
87
+ dill/tests/test_objects.py,sha256=pPAth0toC_UWztuKHC7NZlsRBb0g_gSAt70UbUtXEXo,1931
88
+ dill/tests/test_properties.py,sha256=h35c-lYir1JG6oLPtrA0eYE0xoSohIimsA3yIfRw6yA,1346
89
+ dill/tests/test_pycapsule.py,sha256=EXFyB6g1Wx9O9LM6StIeUKhrhln4_hou1xrtGwkt4Cw,1417
90
+ dill/tests/test_recursive.py,sha256=bfr-BsK1Xu0PU7l2srHsDXdY2l1LeM3L3w7NraXO0cc,4182
91
+ dill/tests/test_registered.py,sha256=J3oku053VfdJgYh4Z5_kyFRf-C52JglIzjcyxEaYOhk,1573
92
+ dill/tests/test_restricted.py,sha256=xLMIae8sYJksAj9hKKyHFHIL8vtbGpFeOULz59snYM4,783
93
+ dill/tests/test_selected.py,sha256=Hp-AAd6Qp5FJZ-vY_Bbejo5Rg6xFstec5QkSg5D7Aac,3218
94
+ dill/tests/test_session.py,sha256=KoSPvs4c4VJ8mFMF7EUlD_3GwcOhhipt9fqHr--Go-4,10161
95
+ dill/tests/test_source.py,sha256=wZTYBbpzUwj3Mz5OjrHQKfskaVVwuy2UQDg5p2wLbT4,6036
96
+ dill/tests/test_temp.py,sha256=F_7nJkSetLIBSAYMw1-hYh03iVrEYwGs-4GIUzoBOfY,2619
97
+ dill/tests/test_weakref.py,sha256=mrjZP5aPtUP1wBD6ibPsDsfI9ffmq_Ykt7ltoodi5Lg,1602
lib/python3.12/site-packages/dill-0.3.8.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.37.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
lib/python3.12/site-packages/dill-0.3.8.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ dill
lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/METADATA ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: fsspec
3
+ Version: 2025.3.0
4
+ Summary: File-system specification
5
+ Project-URL: Changelog, https://filesystem-spec.readthedocs.io/en/latest/changelog.html
6
+ Project-URL: Documentation, https://filesystem-spec.readthedocs.io/en/latest/
7
+ Project-URL: Homepage, https://github.com/fsspec/filesystem_spec
8
+ Maintainer-email: Martin Durant <mdurant@anaconda.com>
9
+ License: BSD 3-Clause License
10
+
11
+ Copyright (c) 2018, Martin Durant
12
+ All rights reserved.
13
+
14
+ Redistribution and use in source and binary forms, with or without
15
+ modification, are permitted provided that the following conditions are met:
16
+
17
+ * Redistributions of source code must retain the above copyright notice, this
18
+ list of conditions and the following disclaimer.
19
+
20
+ * Redistributions in binary form must reproduce the above copyright notice,
21
+ this list of conditions and the following disclaimer in the documentation
22
+ and/or other materials provided with the distribution.
23
+
24
+ * Neither the name of the copyright holder nor the names of its
25
+ contributors may be used to endorse or promote products derived from
26
+ this software without specific prior written permission.
27
+
28
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
32
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
+ License-File: LICENSE
39
+ Keywords: file
40
+ Classifier: Development Status :: 4 - Beta
41
+ Classifier: Intended Audience :: Developers
42
+ Classifier: License :: OSI Approved :: BSD License
43
+ Classifier: Operating System :: OS Independent
44
+ Classifier: Programming Language :: Python :: 3.8
45
+ Classifier: Programming Language :: Python :: 3.9
46
+ Classifier: Programming Language :: Python :: 3.10
47
+ Classifier: Programming Language :: Python :: 3.11
48
+ Classifier: Programming Language :: Python :: 3.12
49
+ Classifier: Programming Language :: Python :: 3.13
50
+ Requires-Python: >=3.8
51
+ Provides-Extra: abfs
52
+ Requires-Dist: adlfs; extra == 'abfs'
53
+ Provides-Extra: adl
54
+ Requires-Dist: adlfs; extra == 'adl'
55
+ Provides-Extra: arrow
56
+ Requires-Dist: pyarrow>=1; extra == 'arrow'
57
+ Provides-Extra: dask
58
+ Requires-Dist: dask; extra == 'dask'
59
+ Requires-Dist: distributed; extra == 'dask'
60
+ Provides-Extra: dev
61
+ Requires-Dist: pre-commit; extra == 'dev'
62
+ Requires-Dist: ruff; extra == 'dev'
63
+ Provides-Extra: doc
64
+ Requires-Dist: numpydoc; extra == 'doc'
65
+ Requires-Dist: sphinx; extra == 'doc'
66
+ Requires-Dist: sphinx-design; extra == 'doc'
67
+ Requires-Dist: sphinx-rtd-theme; extra == 'doc'
68
+ Requires-Dist: yarl; extra == 'doc'
69
+ Provides-Extra: dropbox
70
+ Requires-Dist: dropbox; extra == 'dropbox'
71
+ Requires-Dist: dropboxdrivefs; extra == 'dropbox'
72
+ Requires-Dist: requests; extra == 'dropbox'
73
+ Provides-Extra: entrypoints
74
+ Provides-Extra: full
75
+ Requires-Dist: adlfs; extra == 'full'
76
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'full'
77
+ Requires-Dist: dask; extra == 'full'
78
+ Requires-Dist: distributed; extra == 'full'
79
+ Requires-Dist: dropbox; extra == 'full'
80
+ Requires-Dist: dropboxdrivefs; extra == 'full'
81
+ Requires-Dist: fusepy; extra == 'full'
82
+ Requires-Dist: gcsfs; extra == 'full'
83
+ Requires-Dist: libarchive-c; extra == 'full'
84
+ Requires-Dist: ocifs; extra == 'full'
85
+ Requires-Dist: panel; extra == 'full'
86
+ Requires-Dist: paramiko; extra == 'full'
87
+ Requires-Dist: pyarrow>=1; extra == 'full'
88
+ Requires-Dist: pygit2; extra == 'full'
89
+ Requires-Dist: requests; extra == 'full'
90
+ Requires-Dist: s3fs; extra == 'full'
91
+ Requires-Dist: smbprotocol; extra == 'full'
92
+ Requires-Dist: tqdm; extra == 'full'
93
+ Provides-Extra: fuse
94
+ Requires-Dist: fusepy; extra == 'fuse'
95
+ Provides-Extra: gcs
96
+ Requires-Dist: gcsfs; extra == 'gcs'
97
+ Provides-Extra: git
98
+ Requires-Dist: pygit2; extra == 'git'
99
+ Provides-Extra: github
100
+ Requires-Dist: requests; extra == 'github'
101
+ Provides-Extra: gs
102
+ Requires-Dist: gcsfs; extra == 'gs'
103
+ Provides-Extra: gui
104
+ Requires-Dist: panel; extra == 'gui'
105
+ Provides-Extra: hdfs
106
+ Requires-Dist: pyarrow>=1; extra == 'hdfs'
107
+ Provides-Extra: http
108
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'http'
109
+ Provides-Extra: libarchive
110
+ Requires-Dist: libarchive-c; extra == 'libarchive'
111
+ Provides-Extra: oci
112
+ Requires-Dist: ocifs; extra == 'oci'
113
+ Provides-Extra: s3
114
+ Requires-Dist: s3fs; extra == 's3'
115
+ Provides-Extra: sftp
116
+ Requires-Dist: paramiko; extra == 'sftp'
117
+ Provides-Extra: smb
118
+ Requires-Dist: smbprotocol; extra == 'smb'
119
+ Provides-Extra: ssh
120
+ Requires-Dist: paramiko; extra == 'ssh'
121
+ Provides-Extra: test
122
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'test'
123
+ Requires-Dist: numpy; extra == 'test'
124
+ Requires-Dist: pytest; extra == 'test'
125
+ Requires-Dist: pytest-asyncio!=0.22.0; extra == 'test'
126
+ Requires-Dist: pytest-benchmark; extra == 'test'
127
+ Requires-Dist: pytest-cov; extra == 'test'
128
+ Requires-Dist: pytest-mock; extra == 'test'
129
+ Requires-Dist: pytest-recording; extra == 'test'
130
+ Requires-Dist: pytest-rerunfailures; extra == 'test'
131
+ Requires-Dist: requests; extra == 'test'
132
+ Provides-Extra: test-downstream
133
+ Requires-Dist: aiobotocore<3.0.0,>=2.5.4; extra == 'test-downstream'
134
+ Requires-Dist: dask[dataframe,test]; extra == 'test-downstream'
135
+ Requires-Dist: moto[server]<5,>4; extra == 'test-downstream'
136
+ Requires-Dist: pytest-timeout; extra == 'test-downstream'
137
+ Requires-Dist: xarray; extra == 'test-downstream'
138
+ Provides-Extra: test-full
139
+ Requires-Dist: adlfs; extra == 'test-full'
140
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'test-full'
141
+ Requires-Dist: cloudpickle; extra == 'test-full'
142
+ Requires-Dist: dask; extra == 'test-full'
143
+ Requires-Dist: distributed; extra == 'test-full'
144
+ Requires-Dist: dropbox; extra == 'test-full'
145
+ Requires-Dist: dropboxdrivefs; extra == 'test-full'
146
+ Requires-Dist: fastparquet; extra == 'test-full'
147
+ Requires-Dist: fusepy; extra == 'test-full'
148
+ Requires-Dist: gcsfs; extra == 'test-full'
149
+ Requires-Dist: jinja2; extra == 'test-full'
150
+ Requires-Dist: kerchunk; extra == 'test-full'
151
+ Requires-Dist: libarchive-c; extra == 'test-full'
152
+ Requires-Dist: lz4; extra == 'test-full'
153
+ Requires-Dist: notebook; extra == 'test-full'
154
+ Requires-Dist: numpy; extra == 'test-full'
155
+ Requires-Dist: ocifs; extra == 'test-full'
156
+ Requires-Dist: pandas; extra == 'test-full'
157
+ Requires-Dist: panel; extra == 'test-full'
158
+ Requires-Dist: paramiko; extra == 'test-full'
159
+ Requires-Dist: pyarrow; extra == 'test-full'
160
+ Requires-Dist: pyarrow>=1; extra == 'test-full'
161
+ Requires-Dist: pyftpdlib; extra == 'test-full'
162
+ Requires-Dist: pygit2; extra == 'test-full'
163
+ Requires-Dist: pytest; extra == 'test-full'
164
+ Requires-Dist: pytest-asyncio!=0.22.0; extra == 'test-full'
165
+ Requires-Dist: pytest-benchmark; extra == 'test-full'
166
+ Requires-Dist: pytest-cov; extra == 'test-full'
167
+ Requires-Dist: pytest-mock; extra == 'test-full'
168
+ Requires-Dist: pytest-recording; extra == 'test-full'
169
+ Requires-Dist: pytest-rerunfailures; extra == 'test-full'
170
+ Requires-Dist: python-snappy; extra == 'test-full'
171
+ Requires-Dist: requests; extra == 'test-full'
172
+ Requires-Dist: smbprotocol; extra == 'test-full'
173
+ Requires-Dist: tqdm; extra == 'test-full'
174
+ Requires-Dist: urllib3; extra == 'test-full'
175
+ Requires-Dist: zarr; extra == 'test-full'
176
+ Requires-Dist: zstandard; extra == 'test-full'
177
+ Provides-Extra: tqdm
178
+ Requires-Dist: tqdm; extra == 'tqdm'
179
+ Description-Content-Type: text/markdown
180
+
181
+ # filesystem_spec
182
+
183
+ [![PyPI version](https://badge.fury.io/py/fsspec.svg)](https://pypi.python.org/pypi/fsspec/)
184
+ [![Anaconda-Server Badge](https://anaconda.org/conda-forge/fsspec/badges/version.svg)](https://anaconda.org/conda-forge/fsspec)
185
+ ![Build](https://github.com/fsspec/filesystem_spec/workflows/CI/badge.svg)
186
+ [![Docs](https://readthedocs.org/projects/filesystem-spec/badge/?version=latest)](https://filesystem-spec.readthedocs.io/en/latest/?badge=latest)
187
+
188
+ A specification for pythonic filesystems.
189
+
190
+ ## Install
191
+
192
+ ```bash
193
+ pip install fsspec
194
+ ```
195
+
196
+ would install the base fsspec. Various optionally supported features might require specification of custom
197
+ extra require, e.g. `pip install fsspec[ssh]` will install dependencies for `ssh` backends support.
198
+ Use `pip install fsspec[full]` for installation of all known extra dependencies.
199
+
200
+ Up-to-date package also provided through conda-forge distribution:
201
+
202
+ ```bash
203
+ conda install -c conda-forge fsspec
204
+ ```
205
+
206
+
207
+ ## Purpose
208
+
209
+ To produce a template or specification for a file-system interface, that specific implementations should follow,
210
+ so that applications making use of them can rely on a common behaviour and not have to worry about the specific
211
+ internal implementation decisions with any given backend. Many such implementations are included in this package,
212
+ or in sister projects such as `s3fs` and `gcsfs`.
213
+
214
+ In addition, if this is well-designed, then additional functionality, such as a key-value store or FUSE
215
+ mounting of the file-system implementation may be available for all implementations "for free".
216
+
217
+ ## Documentation
218
+
219
+ Please refer to [RTD](https://filesystem-spec.readthedocs.io/en/latest/?badge=latest)
220
+
221
+ ## Develop
222
+
223
+ fsspec uses GitHub Actions for CI. Environment files can be found
224
+ in the "ci/" directory. Note that the main environment is called "py38",
225
+ but it is expected that the version of python installed be adjustable at
226
+ CI runtime. For local use, pick a version suitable for you.
227
+
228
+ ```bash
229
+ # For a new environment (mamba / conda).
230
+ mamba create -n fsspec -c conda-forge python=3.9 -y
231
+ conda activate fsspec
232
+
233
+ # Standard dev install with docs and tests.
234
+ pip install -e ".[dev,doc,test]"
235
+
236
+ # Full tests except for downstream
237
+ pip install s3fs
238
+ pip uninstall s3fs
239
+ pip install -e .[dev,doc,test_full]
240
+ pip install s3fs --no-deps
241
+ pytest -v
242
+
243
+ # Downstream tests.
244
+ sh install_s3fs.sh
245
+ # Windows powershell.
246
+ install_s3fs.sh
247
+ ```
248
+
249
+ ### Testing
250
+
251
+ Tests can be run in the dev environment, if activated, via ``pytest fsspec``.
252
+
253
+ The full fsspec suite requires a system-level docker, docker-compose, and fuse
254
+ installation. If only making changes to one backend implementation, it is
255
+ not generally necessary to run all tests locally.
256
+
257
+ It is expected that contributors ensure that any change to fsspec does not
258
+ cause issues or regressions for either other fsspec-related packages such
259
+ as gcsfs and s3fs, nor for downstream users of fsspec. The "downstream" CI
260
+ run and corresponding environment file run a set of tests from the dask
261
+ test suite, and very minimal tests against pandas and zarr from the
262
+ test_downstream.py module in this repo.
263
+
264
+ ### Code Formatting
265
+
266
+ fsspec uses [Black](https://black.readthedocs.io/en/stable) to ensure
267
+ a consistent code format throughout the project.
268
+ Run ``black fsspec`` from the root of the filesystem_spec repository to
269
+ auto-format your code. Additionally, many editors have plugins that will apply
270
+ ``black`` as you edit files. ``black`` is included in the ``tox`` environments.
271
+
272
+ Optionally, you may wish to setup [pre-commit hooks](https://pre-commit.com) to
273
+ automatically run ``black`` when you make a git commit.
274
+ Run ``pre-commit install --install-hooks`` from the root of the
275
+ filesystem_spec repository to setup pre-commit hooks. ``black`` will now be run
276
+ before you commit, reformatting any changed files. You can format without
277
+ committing via ``pre-commit run`` or skip these checks with ``git commit
278
+ --no-verify``.
lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/RECORD ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fsspec-2025.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ fsspec-2025.3.0.dist-info/METADATA,sha256=L2OjjikjNWpjvp8i5_ec515Cd09eUi8qZ_3peQmWG8M,11747
3
+ fsspec-2025.3.0.dist-info/RECORD,,
4
+ fsspec-2025.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
5
+ fsspec-2025.3.0.dist-info/licenses/LICENSE,sha256=LcNUls5TpzB5FcAIqESq1T53K0mzTN0ARFBnaRQH7JQ,1513
6
+ fsspec/__init__.py,sha256=l9MJaNNV2d4wKpCtMvXDr55n92DkdrAayGy3F9ICjzk,1998
7
+ fsspec/__pycache__/__init__.cpython-312.pyc,,
8
+ fsspec/__pycache__/_version.cpython-312.pyc,,
9
+ fsspec/__pycache__/archive.cpython-312.pyc,,
10
+ fsspec/__pycache__/asyn.cpython-312.pyc,,
11
+ fsspec/__pycache__/caching.cpython-312.pyc,,
12
+ fsspec/__pycache__/callbacks.cpython-312.pyc,,
13
+ fsspec/__pycache__/compression.cpython-312.pyc,,
14
+ fsspec/__pycache__/config.cpython-312.pyc,,
15
+ fsspec/__pycache__/conftest.cpython-312.pyc,,
16
+ fsspec/__pycache__/core.cpython-312.pyc,,
17
+ fsspec/__pycache__/dircache.cpython-312.pyc,,
18
+ fsspec/__pycache__/exceptions.cpython-312.pyc,,
19
+ fsspec/__pycache__/fuse.cpython-312.pyc,,
20
+ fsspec/__pycache__/generic.cpython-312.pyc,,
21
+ fsspec/__pycache__/gui.cpython-312.pyc,,
22
+ fsspec/__pycache__/json.cpython-312.pyc,,
23
+ fsspec/__pycache__/mapping.cpython-312.pyc,,
24
+ fsspec/__pycache__/parquet.cpython-312.pyc,,
25
+ fsspec/__pycache__/registry.cpython-312.pyc,,
26
+ fsspec/__pycache__/spec.cpython-312.pyc,,
27
+ fsspec/__pycache__/transaction.cpython-312.pyc,,
28
+ fsspec/__pycache__/utils.cpython-312.pyc,,
29
+ fsspec/_version.py,sha256=mWdw-j-kCQGfmn6901GQSyjFXi2pK3h-NrKTuLRVqCw,517
30
+ fsspec/archive.py,sha256=vM6t_lgV6lBWbBYwpm3S4ofBQFQxUPr5KkDQrrQcQro,2411
31
+ fsspec/asyn.py,sha256=rsnCsFUmBZmKJqg9m-IDWInoQtE4wV0rGDZEXZwuU3c,36500
32
+ fsspec/caching.py,sha256=oHVy9zpy4Oqk5f1t3-Q31bbw0tsmfddGGKLJs__OdKA,32790
33
+ fsspec/callbacks.py,sha256=BDIwLzK6rr_0V5ch557fSzsivCElpdqhXr5dZ9Te-EE,9210
34
+ fsspec/compression.py,sha256=jCSUMJu-zSNyrusnHT0wKXgOd1tTJR6vM126i5SR5Zc,4865
35
+ fsspec/config.py,sha256=LF4Zmu1vhJW7Je9Q-cwkRc3xP7Rhyy7Xnwj26Z6sv2g,4279
36
+ fsspec/conftest.py,sha256=fVfx-NLrH_OZS1TIpYNoPzM7efEcMoL62reHOdYeFCA,1245
37
+ fsspec/core.py,sha256=1tLctwr7sF1VO3djc_UkjhJ8IAEy0TUMH_bb07Sw17E,23828
38
+ fsspec/dircache.py,sha256=YzogWJrhEastHU7vWz-cJiJ7sdtLXFXhEpInGKd4EcM,2717
39
+ fsspec/exceptions.py,sha256=pauSLDMxzTJMOjvX1WEUK0cMyFkrFxpWJsyFywav7A8,331
40
+ fsspec/fuse.py,sha256=Q-3NOOyLqBfYa4Db5E19z_ZY36zzYHtIs1mOUasItBQ,10177
41
+ fsspec/generic.py,sha256=AFbo-mHBt5QJV1Aplg5CJuUiiJ4bNQhcKRuwkZJdWac,13761
42
+ fsspec/gui.py,sha256=xBnHL2-r0LVwhDAtnHoPpXts7jd4Z32peawCJiI-7lI,13975
43
+ fsspec/implementations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ fsspec/implementations/__pycache__/__init__.cpython-312.pyc,,
45
+ fsspec/implementations/__pycache__/arrow.cpython-312.pyc,,
46
+ fsspec/implementations/__pycache__/asyn_wrapper.cpython-312.pyc,,
47
+ fsspec/implementations/__pycache__/cache_mapper.cpython-312.pyc,,
48
+ fsspec/implementations/__pycache__/cache_metadata.cpython-312.pyc,,
49
+ fsspec/implementations/__pycache__/cached.cpython-312.pyc,,
50
+ fsspec/implementations/__pycache__/dask.cpython-312.pyc,,
51
+ fsspec/implementations/__pycache__/data.cpython-312.pyc,,
52
+ fsspec/implementations/__pycache__/dbfs.cpython-312.pyc,,
53
+ fsspec/implementations/__pycache__/dirfs.cpython-312.pyc,,
54
+ fsspec/implementations/__pycache__/ftp.cpython-312.pyc,,
55
+ fsspec/implementations/__pycache__/git.cpython-312.pyc,,
56
+ fsspec/implementations/__pycache__/github.cpython-312.pyc,,
57
+ fsspec/implementations/__pycache__/http.cpython-312.pyc,,
58
+ fsspec/implementations/__pycache__/http_sync.cpython-312.pyc,,
59
+ fsspec/implementations/__pycache__/jupyter.cpython-312.pyc,,
60
+ fsspec/implementations/__pycache__/libarchive.cpython-312.pyc,,
61
+ fsspec/implementations/__pycache__/local.cpython-312.pyc,,
62
+ fsspec/implementations/__pycache__/memory.cpython-312.pyc,,
63
+ fsspec/implementations/__pycache__/reference.cpython-312.pyc,,
64
+ fsspec/implementations/__pycache__/sftp.cpython-312.pyc,,
65
+ fsspec/implementations/__pycache__/smb.cpython-312.pyc,,
66
+ fsspec/implementations/__pycache__/tar.cpython-312.pyc,,
67
+ fsspec/implementations/__pycache__/webhdfs.cpython-312.pyc,,
68
+ fsspec/implementations/__pycache__/zip.cpython-312.pyc,,
69
+ fsspec/implementations/arrow.py,sha256=721Dikne_lV_0tlgk9jyKmHL6W-5MT0h2LKGvOYQTPI,8623
70
+ fsspec/implementations/asyn_wrapper.py,sha256=PNkYdHiLVWwk-GJok5O6dTnhPwDaSU9QTtBTE9CIRec,3082
71
+ fsspec/implementations/cache_mapper.py,sha256=W4wlxyPxZbSp9ItJ0pYRVBMh6bw9eFypgP6kUYuuiI4,2421
72
+ fsspec/implementations/cache_metadata.py,sha256=pcOJYcBQY5OaC7Yhw0F3wjg08QLYApGmoISCrbs59ks,8511
73
+ fsspec/implementations/cached.py,sha256=KA6c4jqrGeeg8WNPLsh8FkL3KeRAQtGLzKw18vSF1CI,32820
74
+ fsspec/implementations/dask.py,sha256=CXZbJzIVOhKV8ILcxuy3bTvcacCueAbyQxmvAkbPkrk,4466
75
+ fsspec/implementations/data.py,sha256=LDLczxRh8h7x39Zjrd-GgzdQHr78yYxDlrv2C9Uxb5E,1658
76
+ fsspec/implementations/dbfs.py,sha256=XwpotuS_ncz3XK1dkUteww9GnTja7HoY91c0m4GUfwI,15092
77
+ fsspec/implementations/dirfs.py,sha256=f1sGnQ9Vf0xTxrXo4jDeBy4Qfq3RTqAEemqBSeb0hwY,12108
78
+ fsspec/implementations/ftp.py,sha256=sorsczLp_2J3ukONsbZY-11sRZP6H5a3V7XXf6o6ip0,11936
79
+ fsspec/implementations/git.py,sha256=4SElW9U5d3k3_ITlvUAx59Yk7XLNRTqkGa2C3hCUkWM,3754
80
+ fsspec/implementations/github.py,sha256=eAn1kJ7VeWR6gVoVRLBYclF_rQDXSJU-xzMXpvPQWqs,8002
81
+ fsspec/implementations/http.py,sha256=_gLt0yGbVOYWvE9pK81WCC-3TgbOMOKJYllBU72ALo8,30138
82
+ fsspec/implementations/http_sync.py,sha256=vHf2_O9RRlaW6k-R4hsS-91BkqyPIlc0zwo_ENNGU4U,30147
83
+ fsspec/implementations/jupyter.py,sha256=B2uj7OEm7yIk-vRSsO37_ND0t0EBvn4B-Su43ibN4Pg,3811
84
+ fsspec/implementations/libarchive.py,sha256=5_I2DiLXwQ1JC8x-K7jXu-tBwhO9dj7tFLnb0bTnVMQ,7102
85
+ fsspec/implementations/local.py,sha256=g2iK8uWPGkSiI6bwmnIRXhJMQvTegCmXZ8Kb8ojhvAo,15543
86
+ fsspec/implementations/memory.py,sha256=cLNrK9wk97sl4Tre9uVDXWj6mEHvvVVIgaVgNA5KVIg,10527
87
+ fsspec/implementations/reference.py,sha256=t23prs_5ugXJnYhLxLlPLPyagrx4_ofZWR_oyX9wd3Q,48703
88
+ fsspec/implementations/sftp.py,sha256=fMY9XZcmpjszQ2tCqO_TPaJesaeD_Dv7ptYzgUPGoO0,5631
89
+ fsspec/implementations/smb.py,sha256=5fhu8h06nOLBPh2c48aT7WBRqh9cEcbIwtyu06wTjec,15236
90
+ fsspec/implementations/tar.py,sha256=dam78Tp_CozybNqCY2JYgGBS3Uc9FuJUAT9oB0lolOs,4111
91
+ fsspec/implementations/webhdfs.py,sha256=G9wGywj7BkZk4Mu9zXu6HaDlEqX4F8Gw1i4k46CP_-o,16769
92
+ fsspec/implementations/zip.py,sha256=9LBMHPft2OutJl2Ft-r9u_z3GptLkc2n91ur2A3bCbg,6072
93
+ fsspec/json.py,sha256=65sQ0Y7mTj33u_Y4IId5up4abQ3bAel4E4QzbKMiQSg,3826
94
+ fsspec/mapping.py,sha256=m2ndB_gtRBXYmNJg0Ie1-BVR75TFleHmIQBzC-yWhjU,8343
95
+ fsspec/parquet.py,sha256=6ibAmG527L5JNFS0VO8BDNlxHdA3bVYqdByeiFgpUVM,19448
96
+ fsspec/registry.py,sha256=Bbur6KJilN62hx_lSRgCx9HlKrv91pLpdEPG7Vzme1M,11566
97
+ fsspec/spec.py,sha256=l7ZEbgLsnrFuS-yrGl9re6ia1Yts1_10RqGV_mT-5P8,76032
98
+ fsspec/tests/abstract/__init__.py,sha256=4xUJrv7gDgc85xAOz1p-V_K1hrsdMWTSa0rviALlJk8,10181
99
+ fsspec/tests/abstract/__pycache__/__init__.cpython-312.pyc,,
100
+ fsspec/tests/abstract/__pycache__/common.cpython-312.pyc,,
101
+ fsspec/tests/abstract/__pycache__/copy.cpython-312.pyc,,
102
+ fsspec/tests/abstract/__pycache__/get.cpython-312.pyc,,
103
+ fsspec/tests/abstract/__pycache__/mv.cpython-312.pyc,,
104
+ fsspec/tests/abstract/__pycache__/open.cpython-312.pyc,,
105
+ fsspec/tests/abstract/__pycache__/pipe.cpython-312.pyc,,
106
+ fsspec/tests/abstract/__pycache__/put.cpython-312.pyc,,
107
+ fsspec/tests/abstract/common.py,sha256=1GQwNo5AONzAnzZj0fWgn8NJPLXALehbsuGxS3FzWVU,4973
108
+ fsspec/tests/abstract/copy.py,sha256=gU5-d97U3RSde35Vp4RxPY4rWwL744HiSrJ8IBOp9-8,19967
109
+ fsspec/tests/abstract/get.py,sha256=vNR4HztvTR7Cj56AMo7_tx7TeYz1Jgr_2Wb8Lv-UiBY,20755
110
+ fsspec/tests/abstract/mv.py,sha256=k8eUEBIrRrGMsBY5OOaDXdGnQUKGwDIfQyduB6YD3Ns,1982
111
+ fsspec/tests/abstract/open.py,sha256=Fi2PBPYLbRqysF8cFm0rwnB41kMdQVYjq8cGyDXp3BU,329
112
+ fsspec/tests/abstract/pipe.py,sha256=LFzIrLCB5GLXf9rzFKJmE8AdG7LQ_h4bJo70r8FLPqM,402
113
+ fsspec/tests/abstract/put.py,sha256=7aih17OKB_IZZh1Mkq1eBDIjobhtMQmI8x-Pw-S_aZk,21201
114
+ fsspec/transaction.py,sha256=xliRG6U2Zf3khG4xcw9WiB-yAoqJSHEGK_VjHOdtgo0,2398
115
+ fsspec/utils.py,sha256=A11t25RnpiQ30RO6xeR0Qqlu3fGj8bnc40jg08tlYSI,22980
lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/WHEEL ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
lib/python3.12/site-packages/fsspec-2025.3.0.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2018, Martin Durant
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/LICENSE ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ BSD 3-Clause License
2
+
3
+ - Copyright (c) 2012-Present, IPython Development Team
4
+
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+
10
+ * Redistributions of source code must retain the above copyright notice, this
11
+ list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ * Neither the name of the copyright holder nor the names of its
18
+ contributors may be used to endorse or promote products derived from
19
+ this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/METADATA ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.3
2
+ Name: ipython_pygments_lexers
3
+ Version: 1.1.1
4
+ Summary: Defines a variety of Pygments lexers for highlighting IPython code.
5
+ Author-email: The IPython Development Team <ipython-dev@python.org>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Classifier: Framework :: IPython
9
+ Classifier: License :: OSI Approved :: BSD License
10
+ Requires-Dist: pygments
11
+ Project-URL: Source, https://github.com/ipython/ipython-pygments-lexers
12
+
13
+ A [Pygments](https://pygments.org/) plugin for IPython code & console sessions
14
+
15
+ [IPython](https://ipython.org/) is an interactive Python shell. Among other features,
16
+ it adds some special convenience syntax, including `%magics`, `!shell commands`
17
+ and `help?`. This package contains lexers for these, to use with the Pygments syntax
18
+ highlighting package.
19
+
20
+ - The `ipython` lexer should be used where only input code is highlighted
21
+ - The `ipythonconsole` lexer works for an IPython session, including code,
22
+ prompts, output and tracebacks.
23
+
24
+ These lexers were previously part of IPython itself (in `IPython.lib.lexers`),
25
+ but have now been moved to a separate package.
26
+
lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/RECORD ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ __pycache__/ipython_pygments_lexers.cpython-312.pyc,,
2
+ ipython_pygments_lexers-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
3
+ ipython_pygments_lexers-1.1.1.dist-info/LICENSE,sha256=sdDbwPp5d000uOLQrskdUNjK8F97QPwiwwEKS9mtK_k,1535
4
+ ipython_pygments_lexers-1.1.1.dist-info/METADATA,sha256=azjAlGvbxHePTjjiKYVHy9fROuupl57E5KQS6r-9-ts,1121
5
+ ipython_pygments_lexers-1.1.1.dist-info/RECORD,,
6
+ ipython_pygments_lexers-1.1.1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
7
+ ipython_pygments_lexers-1.1.1.dist-info/entry_points.txt,sha256=hyhe6r0UvHvZPV9EJvyujIlb8CgtRlQ7R6obhvM_s-Y,170
8
+ ipython_pygments_lexers.py,sha256=IPM8mGgS8w15Y3yCSnkvbKYvGAv67t9OwXHwtaKFCpc,19656
lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/WHEEL ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: flit 3.10.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
lib/python3.12/site-packages/ipython_pygments_lexers-1.1.1.dist-info/entry_points.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [pygments.lexers]
2
+ ipython=ipython_pygments_lexers:IPythonLexer
3
+ ipython3=ipython_pygments_lexers:IPython3Lexer
4
+ ipythonconsole=ipython_pygments_lexers:IPythonConsoleLexer
5
+
lib/python3.12/site-packages/jinja2/__init__.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Jinja is a template engine written in pure Python. It provides a
2
+ non-XML syntax that supports inline expressions and an optional
3
+ sandboxed environment.
4
+ """
5
+
6
+ from .bccache import BytecodeCache as BytecodeCache
7
+ from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache
8
+ from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache
9
+ from .environment import Environment as Environment
10
+ from .environment import Template as Template
11
+ from .exceptions import TemplateAssertionError as TemplateAssertionError
12
+ from .exceptions import TemplateError as TemplateError
13
+ from .exceptions import TemplateNotFound as TemplateNotFound
14
+ from .exceptions import TemplateRuntimeError as TemplateRuntimeError
15
+ from .exceptions import TemplatesNotFound as TemplatesNotFound
16
+ from .exceptions import TemplateSyntaxError as TemplateSyntaxError
17
+ from .exceptions import UndefinedError as UndefinedError
18
+ from .loaders import BaseLoader as BaseLoader
19
+ from .loaders import ChoiceLoader as ChoiceLoader
20
+ from .loaders import DictLoader as DictLoader
21
+ from .loaders import FileSystemLoader as FileSystemLoader
22
+ from .loaders import FunctionLoader as FunctionLoader
23
+ from .loaders import ModuleLoader as ModuleLoader
24
+ from .loaders import PackageLoader as PackageLoader
25
+ from .loaders import PrefixLoader as PrefixLoader
26
+ from .runtime import ChainableUndefined as ChainableUndefined
27
+ from .runtime import DebugUndefined as DebugUndefined
28
+ from .runtime import make_logging_undefined as make_logging_undefined
29
+ from .runtime import StrictUndefined as StrictUndefined
30
+ from .runtime import Undefined as Undefined
31
+ from .utils import clear_caches as clear_caches
32
+ from .utils import is_undefined as is_undefined
33
+ from .utils import pass_context as pass_context
34
+ from .utils import pass_environment as pass_environment
35
+ from .utils import pass_eval_context as pass_eval_context
36
+ from .utils import select_autoescape as select_autoescape
37
+
38
+ __version__ = "3.1.6"
lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.65 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc ADDED
Binary file (2.14 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc ADDED
Binary file (4.98 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc ADDED
Binary file (19.3 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc ADDED
Binary file (1.56 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc ADDED
Binary file (6.57 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc ADDED
Binary file (1.61 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc ADDED
Binary file (76.6 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc ADDED
Binary file (7.72 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc ADDED
Binary file (41.9 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc ADDED
Binary file (72.3 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc ADDED
Binary file (19.1 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc ADDED
Binary file (32.1 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc ADDED
Binary file (32.3 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc ADDED
Binary file (5.47 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc ADDED
Binary file (7.02 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc ADDED
Binary file (58.2 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc ADDED
Binary file (2.69 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc ADDED
Binary file (61.2 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc ADDED
Binary file (48.9 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc ADDED
Binary file (18.1 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc ADDED
Binary file (9.05 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc ADDED
Binary file (34.8 kB). View file
 
lib/python3.12/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc ADDED
Binary file (5.35 kB). View file
 
lib/python3.12/site-packages/jinja2/_identifier.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import re
2
+
3
+ # generated by scripts/generate_identifier_pattern.py
4
+ pattern = re.compile(
5
+ r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𐴤-𐽆𐴧-𐽐𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑄴𑅅𑅆𑅳𑆀-𑆂𑆳-𑇀𑇉-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌻𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑑞𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑠬-𑠺𑨁-𑨊𑨳-𑨹𑨻-𑨾𑩇𑩑-𑩛𑪊-𑪙𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𑴱-𑴶𑴺𑴼𑴽𑴿-𑵅𑵇𑶊-𑶎𑶐𑶑𑶓-𑶗𑻳-𑻶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950
6
+ )
lib/python3.12/site-packages/jinja2/async_utils.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import inspect
2
+ import typing as t
3
+ from functools import WRAPPER_ASSIGNMENTS
4
+ from functools import wraps
5
+
6
+ from .utils import _PassArg
7
+ from .utils import pass_eval_context
8
+
9
+ if t.TYPE_CHECKING:
10
+ import typing_extensions as te
11
+
12
+ V = t.TypeVar("V")
13
+
14
+
15
+ def async_variant(normal_func): # type: ignore
16
+ def decorator(async_func): # type: ignore
17
+ pass_arg = _PassArg.from_obj(normal_func)
18
+ need_eval_context = pass_arg is None
19
+
20
+ if pass_arg is _PassArg.environment:
21
+
22
+ def is_async(args: t.Any) -> bool:
23
+ return t.cast(bool, args[0].is_async)
24
+
25
+ else:
26
+
27
+ def is_async(args: t.Any) -> bool:
28
+ return t.cast(bool, args[0].environment.is_async)
29
+
30
+ # Take the doc and annotations from the sync function, but the
31
+ # name from the async function. Pallets-Sphinx-Themes
32
+ # build_function_directive expects __wrapped__ to point to the
33
+ # sync function.
34
+ async_func_attrs = ("__module__", "__name__", "__qualname__")
35
+ normal_func_attrs = tuple(set(WRAPPER_ASSIGNMENTS).difference(async_func_attrs))
36
+
37
+ @wraps(normal_func, assigned=normal_func_attrs)
38
+ @wraps(async_func, assigned=async_func_attrs, updated=())
39
+ def wrapper(*args, **kwargs): # type: ignore
40
+ b = is_async(args)
41
+
42
+ if need_eval_context:
43
+ args = args[1:]
44
+
45
+ if b:
46
+ return async_func(*args, **kwargs)
47
+
48
+ return normal_func(*args, **kwargs)
49
+
50
+ if need_eval_context:
51
+ wrapper = pass_eval_context(wrapper)
52
+
53
+ wrapper.jinja_async_variant = True # type: ignore[attr-defined]
54
+ return wrapper
55
+
56
+ return decorator
57
+
58
+
59
+ _common_primitives = {int, float, bool, str, list, dict, tuple, type(None)}
60
+
61
+
62
+ async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V":
63
+ # Avoid a costly call to isawaitable
64
+ if type(value) in _common_primitives:
65
+ return t.cast("V", value)
66
+
67
+ if inspect.isawaitable(value):
68
+ return await t.cast("t.Awaitable[V]", value)
69
+
70
+ return value
71
+
72
+
73
+ class _IteratorToAsyncIterator(t.Generic[V]):
74
+ def __init__(self, iterator: "t.Iterator[V]"):
75
+ self._iterator = iterator
76
+
77
+ def __aiter__(self) -> "te.Self":
78
+ return self
79
+
80
+ async def __anext__(self) -> V:
81
+ try:
82
+ return next(self._iterator)
83
+ except StopIteration as e:
84
+ raise StopAsyncIteration(e.value) from e
85
+
86
+
87
+ def auto_aiter(
88
+ iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
89
+ ) -> "t.AsyncIterator[V]":
90
+ if hasattr(iterable, "__aiter__"):
91
+ return iterable.__aiter__()
92
+ else:
93
+ return _IteratorToAsyncIterator(iter(iterable))
94
+
95
+
96
+ async def auto_to_list(
97
+ value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
98
+ ) -> t.List["V"]:
99
+ return [x async for x in auto_aiter(value)]
lib/python3.12/site-packages/jinja2/bccache.py ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """The optional bytecode cache system. This is useful if you have very
2
+ complex template situations and the compilation of all those templates
3
+ slows down your application too much.
4
+
5
+ Situations where this is useful are often forking web applications that
6
+ are initialized on the first request.
7
+ """
8
+
9
+ import errno
10
+ import fnmatch
11
+ import marshal
12
+ import os
13
+ import pickle
14
+ import stat
15
+ import sys
16
+ import tempfile
17
+ import typing as t
18
+ from hashlib import sha1
19
+ from io import BytesIO
20
+ from types import CodeType
21
+
22
+ if t.TYPE_CHECKING:
23
+ import typing_extensions as te
24
+
25
+ from .environment import Environment
26
+
27
+ class _MemcachedClient(te.Protocol):
28
+ def get(self, key: str) -> bytes: ...
29
+
30
+ def set(
31
+ self, key: str, value: bytes, timeout: t.Optional[int] = None
32
+ ) -> None: ...
33
+
34
+
35
+ bc_version = 5
36
+ # Magic bytes to identify Jinja bytecode cache files. Contains the
37
+ # Python major and minor version to avoid loading incompatible bytecode
38
+ # if a project upgrades its Python version.
39
+ bc_magic = (
40
+ b"j2"
41
+ + pickle.dumps(bc_version, 2)
42
+ + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2)
43
+ )
44
+
45
+
46
+ class Bucket:
47
+ """Buckets are used to store the bytecode for one template. It's created
48
+ and initialized by the bytecode cache and passed to the loading functions.
49
+
50
+ The buckets get an internal checksum from the cache assigned and use this
51
+ to automatically reject outdated cache material. Individual bytecode
52
+ cache subclasses don't have to care about cache invalidation.
53
+ """
54
+
55
+ def __init__(self, environment: "Environment", key: str, checksum: str) -> None:
56
+ self.environment = environment
57
+ self.key = key
58
+ self.checksum = checksum
59
+ self.reset()
60
+
61
+ def reset(self) -> None:
62
+ """Resets the bucket (unloads the bytecode)."""
63
+ self.code: t.Optional[CodeType] = None
64
+
65
+ def load_bytecode(self, f: t.BinaryIO) -> None:
66
+ """Loads bytecode from a file or file like object."""
67
+ # make sure the magic header is correct
68
+ magic = f.read(len(bc_magic))
69
+ if magic != bc_magic:
70
+ self.reset()
71
+ return
72
+ # the source code of the file changed, we need to reload
73
+ checksum = pickle.load(f)
74
+ if self.checksum != checksum:
75
+ self.reset()
76
+ return
77
+ # if marshal_load fails then we need to reload
78
+ try:
79
+ self.code = marshal.load(f)
80
+ except (EOFError, ValueError, TypeError):
81
+ self.reset()
82
+ return
83
+
84
+ def write_bytecode(self, f: t.IO[bytes]) -> None:
85
+ """Dump the bytecode into the file or file like object passed."""
86
+ if self.code is None:
87
+ raise TypeError("can't write empty bucket")
88
+ f.write(bc_magic)
89
+ pickle.dump(self.checksum, f, 2)
90
+ marshal.dump(self.code, f)
91
+
92
+ def bytecode_from_string(self, string: bytes) -> None:
93
+ """Load bytecode from bytes."""
94
+ self.load_bytecode(BytesIO(string))
95
+
96
+ def bytecode_to_string(self) -> bytes:
97
+ """Return the bytecode as bytes."""
98
+ out = BytesIO()
99
+ self.write_bytecode(out)
100
+ return out.getvalue()
101
+
102
+
103
+ class BytecodeCache:
104
+ """To implement your own bytecode cache you have to subclass this class
105
+ and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of
106
+ these methods are passed a :class:`~jinja2.bccache.Bucket`.
107
+
108
+ A very basic bytecode cache that saves the bytecode on the file system::
109
+
110
+ from os import path
111
+
112
+ class MyCache(BytecodeCache):
113
+
114
+ def __init__(self, directory):
115
+ self.directory = directory
116
+
117
+ def load_bytecode(self, bucket):
118
+ filename = path.join(self.directory, bucket.key)
119
+ if path.exists(filename):
120
+ with open(filename, 'rb') as f:
121
+ bucket.load_bytecode(f)
122
+
123
+ def dump_bytecode(self, bucket):
124
+ filename = path.join(self.directory, bucket.key)
125
+ with open(filename, 'wb') as f:
126
+ bucket.write_bytecode(f)
127
+
128
+ A more advanced version of a filesystem based bytecode cache is part of
129
+ Jinja.
130
+ """
131
+
132
+ def load_bytecode(self, bucket: Bucket) -> None:
133
+ """Subclasses have to override this method to load bytecode into a
134
+ bucket. If they are not able to find code in the cache for the
135
+ bucket, it must not do anything.
136
+ """
137
+ raise NotImplementedError()
138
+
139
+ def dump_bytecode(self, bucket: Bucket) -> None:
140
+ """Subclasses have to override this method to write the bytecode
141
+ from a bucket back to the cache. If it unable to do so it must not
142
+ fail silently but raise an exception.
143
+ """
144
+ raise NotImplementedError()
145
+
146
+ def clear(self) -> None:
147
+ """Clears the cache. This method is not used by Jinja but should be
148
+ implemented to allow applications to clear the bytecode cache used
149
+ by a particular environment.
150
+ """
151
+
152
+ def get_cache_key(
153
+ self, name: str, filename: t.Optional[t.Union[str]] = None
154
+ ) -> str:
155
+ """Returns the unique hash key for this template name."""
156
+ hash = sha1(name.encode("utf-8"))
157
+
158
+ if filename is not None:
159
+ hash.update(f"|{filename}".encode())
160
+
161
+ return hash.hexdigest()
162
+
163
+ def get_source_checksum(self, source: str) -> str:
164
+ """Returns a checksum for the source."""
165
+ return sha1(source.encode("utf-8")).hexdigest()
166
+
167
+ def get_bucket(
168
+ self,
169
+ environment: "Environment",
170
+ name: str,
171
+ filename: t.Optional[str],
172
+ source: str,
173
+ ) -> Bucket:
174
+ """Return a cache bucket for the given template. All arguments are
175
+ mandatory but filename may be `None`.
176
+ """
177
+ key = self.get_cache_key(name, filename)
178
+ checksum = self.get_source_checksum(source)
179
+ bucket = Bucket(environment, key, checksum)
180
+ self.load_bytecode(bucket)
181
+ return bucket
182
+
183
+ def set_bucket(self, bucket: Bucket) -> None:
184
+ """Put the bucket into the cache."""
185
+ self.dump_bytecode(bucket)
186
+
187
+
188
+ class FileSystemBytecodeCache(BytecodeCache):
189
+ """A bytecode cache that stores bytecode on the filesystem. It accepts
190
+ two arguments: The directory where the cache items are stored and a
191
+ pattern string that is used to build the filename.
192
+
193
+ If no directory is specified a default cache directory is selected. On
194
+ Windows the user's temp directory is used, on UNIX systems a directory
195
+ is created for the user in the system temp directory.
196
+
197
+ The pattern can be used to have multiple separate caches operate on the
198
+ same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s``
199
+ is replaced with the cache key.
200
+
201
+ >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')
202
+
203
+ This bytecode cache supports clearing of the cache using the clear method.
204
+ """
205
+
206
+ def __init__(
207
+ self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache"
208
+ ) -> None:
209
+ if directory is None:
210
+ directory = self._get_default_cache_dir()
211
+ self.directory = directory
212
+ self.pattern = pattern
213
+
214
+ def _get_default_cache_dir(self) -> str:
215
+ def _unsafe_dir() -> "te.NoReturn":
216
+ raise RuntimeError(
217
+ "Cannot determine safe temp directory. You "
218
+ "need to explicitly provide one."
219
+ )
220
+
221
+ tmpdir = tempfile.gettempdir()
222
+
223
+ # On windows the temporary directory is used specific unless
224
+ # explicitly forced otherwise. We can just use that.
225
+ if os.name == "nt":
226
+ return tmpdir
227
+ if not hasattr(os, "getuid"):
228
+ _unsafe_dir()
229
+
230
+ dirname = f"_jinja2-cache-{os.getuid()}"
231
+ actual_dir = os.path.join(tmpdir, dirname)
232
+
233
+ try:
234
+ os.mkdir(actual_dir, stat.S_IRWXU)
235
+ except OSError as e:
236
+ if e.errno != errno.EEXIST:
237
+ raise
238
+ try:
239
+ os.chmod(actual_dir, stat.S_IRWXU)
240
+ actual_dir_stat = os.lstat(actual_dir)
241
+ if (
242
+ actual_dir_stat.st_uid != os.getuid()
243
+ or not stat.S_ISDIR(actual_dir_stat.st_mode)
244
+ or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU
245
+ ):
246
+ _unsafe_dir()
247
+ except OSError as e:
248
+ if e.errno != errno.EEXIST:
249
+ raise
250
+
251
+ actual_dir_stat = os.lstat(actual_dir)
252
+ if (
253
+ actual_dir_stat.st_uid != os.getuid()
254
+ or not stat.S_ISDIR(actual_dir_stat.st_mode)
255
+ or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU
256
+ ):
257
+ _unsafe_dir()
258
+
259
+ return actual_dir
260
+
261
+ def _get_cache_filename(self, bucket: Bucket) -> str:
262
+ return os.path.join(self.directory, self.pattern % (bucket.key,))
263
+
264
+ def load_bytecode(self, bucket: Bucket) -> None:
265
+ filename = self._get_cache_filename(bucket)
266
+
267
+ # Don't test for existence before opening the file, since the
268
+ # file could disappear after the test before the open.
269
+ try:
270
+ f = open(filename, "rb")
271
+ except (FileNotFoundError, IsADirectoryError, PermissionError):
272
+ # PermissionError can occur on Windows when an operation is
273
+ # in progress, such as calling clear().
274
+ return
275
+
276
+ with f:
277
+ bucket.load_bytecode(f)
278
+
279
+ def dump_bytecode(self, bucket: Bucket) -> None:
280
+ # Write to a temporary file, then rename to the real name after
281
+ # writing. This avoids another process reading the file before
282
+ # it is fully written.
283
+ name = self._get_cache_filename(bucket)
284
+ f = tempfile.NamedTemporaryFile(
285
+ mode="wb",
286
+ dir=os.path.dirname(name),
287
+ prefix=os.path.basename(name),
288
+ suffix=".tmp",
289
+ delete=False,
290
+ )
291
+
292
+ def remove_silent() -> None:
293
+ try:
294
+ os.remove(f.name)
295
+ except OSError:
296
+ # Another process may have called clear(). On Windows,
297
+ # another program may be holding the file open.
298
+ pass
299
+
300
+ try:
301
+ with f:
302
+ bucket.write_bytecode(f)
303
+ except BaseException:
304
+ remove_silent()
305
+ raise
306
+
307
+ try:
308
+ os.replace(f.name, name)
309
+ except OSError:
310
+ # Another process may have called clear(). On Windows,
311
+ # another program may be holding the file open.
312
+ remove_silent()
313
+ except BaseException:
314
+ remove_silent()
315
+ raise
316
+
317
+ def clear(self) -> None:
318
+ # imported lazily here because google app-engine doesn't support
319
+ # write access on the file system and the function does not exist
320
+ # normally.
321
+ from os import remove
322
+
323
+ files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",))
324
+ for filename in files:
325
+ try:
326
+ remove(os.path.join(self.directory, filename))
327
+ except OSError:
328
+ pass
329
+
330
+
331
+ class MemcachedBytecodeCache(BytecodeCache):
332
+ """This class implements a bytecode cache that uses a memcache cache for
333
+ storing the information. It does not enforce a specific memcache library
334
+ (tummy's memcache or cmemcache) but will accept any class that provides
335
+ the minimal interface required.
336
+
337
+ Libraries compatible with this class:
338
+
339
+ - `cachelib <https://github.com/pallets/cachelib>`_
340
+ - `python-memcached <https://pypi.org/project/python-memcached/>`_
341
+
342
+ (Unfortunately the django cache interface is not compatible because it
343
+ does not support storing binary data, only text. You can however pass
344
+ the underlying cache client to the bytecode cache which is available
345
+ as `django.core.cache.cache._client`.)
346
+
347
+ The minimal interface for the client passed to the constructor is this:
348
+
349
+ .. class:: MinimalClientInterface
350
+
351
+ .. method:: set(key, value[, timeout])
352
+
353
+ Stores the bytecode in the cache. `value` is a string and
354
+ `timeout` the timeout of the key. If timeout is not provided
355
+ a default timeout or no timeout should be assumed, if it's
356
+ provided it's an integer with the number of seconds the cache
357
+ item should exist.
358
+
359
+ .. method:: get(key)
360
+
361
+ Returns the value for the cache key. If the item does not
362
+ exist in the cache the return value must be `None`.
363
+
364
+ The other arguments to the constructor are the prefix for all keys that
365
+ is added before the actual cache key and the timeout for the bytecode in
366
+ the cache system. We recommend a high (or no) timeout.
367
+
368
+ This bytecode cache does not support clearing of used items in the cache.
369
+ The clear method is a no-operation function.
370
+
371
+ .. versionadded:: 2.7
372
+ Added support for ignoring memcache errors through the
373
+ `ignore_memcache_errors` parameter.
374
+ """
375
+
376
+ def __init__(
377
+ self,
378
+ client: "_MemcachedClient",
379
+ prefix: str = "jinja2/bytecode/",
380
+ timeout: t.Optional[int] = None,
381
+ ignore_memcache_errors: bool = True,
382
+ ):
383
+ self.client = client
384
+ self.prefix = prefix
385
+ self.timeout = timeout
386
+ self.ignore_memcache_errors = ignore_memcache_errors
387
+
388
+ def load_bytecode(self, bucket: Bucket) -> None:
389
+ try:
390
+ code = self.client.get(self.prefix + bucket.key)
391
+ except Exception:
392
+ if not self.ignore_memcache_errors:
393
+ raise
394
+ else:
395
+ bucket.bytecode_from_string(code)
396
+
397
+ def dump_bytecode(self, bucket: Bucket) -> None:
398
+ key = self.prefix + bucket.key
399
+ value = bucket.bytecode_to_string()
400
+
401
+ try:
402
+ if self.timeout is not None:
403
+ self.client.set(key, value, self.timeout)
404
+ else:
405
+ self.client.set(key, value)
406
+ except Exception:
407
+ if not self.ignore_memcache_errors:
408
+ raise
lib/python3.12/site-packages/jinja2/compiler.py ADDED
@@ -0,0 +1,1998 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Compiles nodes from the parser into Python code."""
2
+
3
+ import typing as t
4
+ from contextlib import contextmanager
5
+ from functools import update_wrapper
6
+ from io import StringIO
7
+ from itertools import chain
8
+ from keyword import iskeyword as is_python_keyword
9
+
10
+ from markupsafe import escape
11
+ from markupsafe import Markup
12
+
13
+ from . import nodes
14
+ from .exceptions import TemplateAssertionError
15
+ from .idtracking import Symbols
16
+ from .idtracking import VAR_LOAD_ALIAS
17
+ from .idtracking import VAR_LOAD_PARAMETER
18
+ from .idtracking import VAR_LOAD_RESOLVE
19
+ from .idtracking import VAR_LOAD_UNDEFINED
20
+ from .nodes import EvalContext
21
+ from .optimizer import Optimizer
22
+ from .utils import _PassArg
23
+ from .utils import concat
24
+ from .visitor import NodeVisitor
25
+
26
+ if t.TYPE_CHECKING:
27
+ import typing_extensions as te
28
+
29
+ from .environment import Environment
30
+
31
+ F = t.TypeVar("F", bound=t.Callable[..., t.Any])
32
+
33
+ operators = {
34
+ "eq": "==",
35
+ "ne": "!=",
36
+ "gt": ">",
37
+ "gteq": ">=",
38
+ "lt": "<",
39
+ "lteq": "<=",
40
+ "in": "in",
41
+ "notin": "not in",
42
+ }
43
+
44
+
45
+ def optimizeconst(f: F) -> F:
46
+ def new_func(
47
+ self: "CodeGenerator", node: nodes.Expr, frame: "Frame", **kwargs: t.Any
48
+ ) -> t.Any:
49
+ # Only optimize if the frame is not volatile
50
+ if self.optimizer is not None and not frame.eval_ctx.volatile:
51
+ new_node = self.optimizer.visit(node, frame.eval_ctx)
52
+
53
+ if new_node != node:
54
+ return self.visit(new_node, frame)
55
+
56
+ return f(self, node, frame, **kwargs)
57
+
58
+ return update_wrapper(new_func, f) # type: ignore[return-value]
59
+
60
+
61
+ def _make_binop(op: str) -> t.Callable[["CodeGenerator", nodes.BinExpr, "Frame"], None]:
62
+ @optimizeconst
63
+ def visitor(self: "CodeGenerator", node: nodes.BinExpr, frame: Frame) -> None:
64
+ if (
65
+ self.environment.sandboxed and op in self.environment.intercepted_binops # type: ignore
66
+ ):
67
+ self.write(f"environment.call_binop(context, {op!r}, ")
68
+ self.visit(node.left, frame)
69
+ self.write(", ")
70
+ self.visit(node.right, frame)
71
+ else:
72
+ self.write("(")
73
+ self.visit(node.left, frame)
74
+ self.write(f" {op} ")
75
+ self.visit(node.right, frame)
76
+
77
+ self.write(")")
78
+
79
+ return visitor
80
+
81
+
82
+ def _make_unop(
83
+ op: str,
84
+ ) -> t.Callable[["CodeGenerator", nodes.UnaryExpr, "Frame"], None]:
85
+ @optimizeconst
86
+ def visitor(self: "CodeGenerator", node: nodes.UnaryExpr, frame: Frame) -> None:
87
+ if (
88
+ self.environment.sandboxed and op in self.environment.intercepted_unops # type: ignore
89
+ ):
90
+ self.write(f"environment.call_unop(context, {op!r}, ")
91
+ self.visit(node.node, frame)
92
+ else:
93
+ self.write("(" + op)
94
+ self.visit(node.node, frame)
95
+
96
+ self.write(")")
97
+
98
+ return visitor
99
+
100
+
101
+ def generate(
102
+ node: nodes.Template,
103
+ environment: "Environment",
104
+ name: t.Optional[str],
105
+ filename: t.Optional[str],
106
+ stream: t.Optional[t.TextIO] = None,
107
+ defer_init: bool = False,
108
+ optimized: bool = True,
109
+ ) -> t.Optional[str]:
110
+ """Generate the python source for a node tree."""
111
+ if not isinstance(node, nodes.Template):
112
+ raise TypeError("Can't compile non template nodes")
113
+
114
+ generator = environment.code_generator_class(
115
+ environment, name, filename, stream, defer_init, optimized
116
+ )
117
+ generator.visit(node)
118
+
119
+ if stream is None:
120
+ return generator.stream.getvalue() # type: ignore
121
+
122
+ return None
123
+
124
+
125
+ def has_safe_repr(value: t.Any) -> bool:
126
+ """Does the node have a safe representation?"""
127
+ if value is None or value is NotImplemented or value is Ellipsis:
128
+ return True
129
+
130
+ if type(value) in {bool, int, float, complex, range, str, Markup}:
131
+ return True
132
+
133
+ if type(value) in {tuple, list, set, frozenset}:
134
+ return all(has_safe_repr(v) for v in value)
135
+
136
+ if type(value) is dict: # noqa E721
137
+ return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items())
138
+
139
+ return False
140
+
141
+
142
+ def find_undeclared(
143
+ nodes: t.Iterable[nodes.Node], names: t.Iterable[str]
144
+ ) -> t.Set[str]:
145
+ """Check if the names passed are accessed undeclared. The return value
146
+ is a set of all the undeclared names from the sequence of names found.
147
+ """
148
+ visitor = UndeclaredNameVisitor(names)
149
+ try:
150
+ for node in nodes:
151
+ visitor.visit(node)
152
+ except VisitorExit:
153
+ pass
154
+ return visitor.undeclared
155
+
156
+
157
+ class MacroRef:
158
+ def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None:
159
+ self.node = node
160
+ self.accesses_caller = False
161
+ self.accesses_kwargs = False
162
+ self.accesses_varargs = False
163
+
164
+
165
+ class Frame:
166
+ """Holds compile time information for us."""
167
+
168
+ def __init__(
169
+ self,
170
+ eval_ctx: EvalContext,
171
+ parent: t.Optional["Frame"] = None,
172
+ level: t.Optional[int] = None,
173
+ ) -> None:
174
+ self.eval_ctx = eval_ctx
175
+
176
+ # the parent of this frame
177
+ self.parent = parent
178
+
179
+ if parent is None:
180
+ self.symbols = Symbols(level=level)
181
+
182
+ # in some dynamic inheritance situations the compiler needs to add
183
+ # write tests around output statements.
184
+ self.require_output_check = False
185
+
186
+ # inside some tags we are using a buffer rather than yield statements.
187
+ # this for example affects {% filter %} or {% macro %}. If a frame
188
+ # is buffered this variable points to the name of the list used as
189
+ # buffer.
190
+ self.buffer: t.Optional[str] = None
191
+
192
+ # the name of the block we're in, otherwise None.
193
+ self.block: t.Optional[str] = None
194
+
195
+ else:
196
+ self.symbols = Symbols(parent.symbols, level=level)
197
+ self.require_output_check = parent.require_output_check
198
+ self.buffer = parent.buffer
199
+ self.block = parent.block
200
+
201
+ # a toplevel frame is the root + soft frames such as if conditions.
202
+ self.toplevel = False
203
+
204
+ # the root frame is basically just the outermost frame, so no if
205
+ # conditions. This information is used to optimize inheritance
206
+ # situations.
207
+ self.rootlevel = False
208
+
209
+ # variables set inside of loops and blocks should not affect outer frames,
210
+ # but they still needs to be kept track of as part of the active context.
211
+ self.loop_frame = False
212
+ self.block_frame = False
213
+
214
+ # track whether the frame is being used in an if-statement or conditional
215
+ # expression as it determines which errors should be raised during runtime
216
+ # or compile time.
217
+ self.soft_frame = False
218
+
219
+ def copy(self) -> "te.Self":
220
+ """Create a copy of the current one."""
221
+ rv = object.__new__(self.__class__)
222
+ rv.__dict__.update(self.__dict__)
223
+ rv.symbols = self.symbols.copy()
224
+ return rv
225
+
226
+ def inner(self, isolated: bool = False) -> "Frame":
227
+ """Return an inner frame."""
228
+ if isolated:
229
+ return Frame(self.eval_ctx, level=self.symbols.level + 1)
230
+ return Frame(self.eval_ctx, self)
231
+
232
+ def soft(self) -> "te.Self":
233
+ """Return a soft frame. A soft frame may not be modified as
234
+ standalone thing as it shares the resources with the frame it
235
+ was created of, but it's not a rootlevel frame any longer.
236
+
237
+ This is only used to implement if-statements and conditional
238
+ expressions.
239
+ """
240
+ rv = self.copy()
241
+ rv.rootlevel = False
242
+ rv.soft_frame = True
243
+ return rv
244
+
245
+ __copy__ = copy
246
+
247
+
248
+ class VisitorExit(RuntimeError):
249
+ """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
250
+
251
+
252
+ class DependencyFinderVisitor(NodeVisitor):
253
+ """A visitor that collects filter and test calls."""
254
+
255
+ def __init__(self) -> None:
256
+ self.filters: t.Set[str] = set()
257
+ self.tests: t.Set[str] = set()
258
+
259
+ def visit_Filter(self, node: nodes.Filter) -> None:
260
+ self.generic_visit(node)
261
+ self.filters.add(node.name)
262
+
263
+ def visit_Test(self, node: nodes.Test) -> None:
264
+ self.generic_visit(node)
265
+ self.tests.add(node.name)
266
+
267
+ def visit_Block(self, node: nodes.Block) -> None:
268
+ """Stop visiting at blocks."""
269
+
270
+
271
+ class UndeclaredNameVisitor(NodeVisitor):
272
+ """A visitor that checks if a name is accessed without being
273
+ declared. This is different from the frame visitor as it will
274
+ not stop at closure frames.
275
+ """
276
+
277
+ def __init__(self, names: t.Iterable[str]) -> None:
278
+ self.names = set(names)
279
+ self.undeclared: t.Set[str] = set()
280
+
281
+ def visit_Name(self, node: nodes.Name) -> None:
282
+ if node.ctx == "load" and node.name in self.names:
283
+ self.undeclared.add(node.name)
284
+ if self.undeclared == self.names:
285
+ raise VisitorExit()
286
+ else:
287
+ self.names.discard(node.name)
288
+
289
+ def visit_Block(self, node: nodes.Block) -> None:
290
+ """Stop visiting a blocks."""
291
+
292
+
293
+ class CompilerExit(Exception):
294
+ """Raised if the compiler encountered a situation where it just
295
+ doesn't make sense to further process the code. Any block that
296
+ raises such an exception is not further processed.
297
+ """
298
+
299
+
300
+ class CodeGenerator(NodeVisitor):
301
+ def __init__(
302
+ self,
303
+ environment: "Environment",
304
+ name: t.Optional[str],
305
+ filename: t.Optional[str],
306
+ stream: t.Optional[t.TextIO] = None,
307
+ defer_init: bool = False,
308
+ optimized: bool = True,
309
+ ) -> None:
310
+ if stream is None:
311
+ stream = StringIO()
312
+ self.environment = environment
313
+ self.name = name
314
+ self.filename = filename
315
+ self.stream = stream
316
+ self.created_block_context = False
317
+ self.defer_init = defer_init
318
+ self.optimizer: t.Optional[Optimizer] = None
319
+
320
+ if optimized:
321
+ self.optimizer = Optimizer(environment)
322
+
323
+ # aliases for imports
324
+ self.import_aliases: t.Dict[str, str] = {}
325
+
326
+ # a registry for all blocks. Because blocks are moved out
327
+ # into the global python scope they are registered here
328
+ self.blocks: t.Dict[str, nodes.Block] = {}
329
+
330
+ # the number of extends statements so far
331
+ self.extends_so_far = 0
332
+
333
+ # some templates have a rootlevel extends. In this case we
334
+ # can safely assume that we're a child template and do some
335
+ # more optimizations.
336
+ self.has_known_extends = False
337
+
338
+ # the current line number
339
+ self.code_lineno = 1
340
+
341
+ # registry of all filters and tests (global, not block local)
342
+ self.tests: t.Dict[str, str] = {}
343
+ self.filters: t.Dict[str, str] = {}
344
+
345
+ # the debug information
346
+ self.debug_info: t.List[t.Tuple[int, int]] = []
347
+ self._write_debug_info: t.Optional[int] = None
348
+
349
+ # the number of new lines before the next write()
350
+ self._new_lines = 0
351
+
352
+ # the line number of the last written statement
353
+ self._last_line = 0
354
+
355
+ # true if nothing was written so far.
356
+ self._first_write = True
357
+
358
+ # used by the `temporary_identifier` method to get new
359
+ # unique, temporary identifier
360
+ self._last_identifier = 0
361
+
362
+ # the current indentation
363
+ self._indentation = 0
364
+
365
+ # Tracks toplevel assignments
366
+ self._assign_stack: t.List[t.Set[str]] = []
367
+
368
+ # Tracks parameter definition blocks
369
+ self._param_def_block: t.List[t.Set[str]] = []
370
+
371
+ # Tracks the current context.
372
+ self._context_reference_stack = ["context"]
373
+
374
+ @property
375
+ def optimized(self) -> bool:
376
+ return self.optimizer is not None
377
+
378
+ # -- Various compilation helpers
379
+
380
+ def fail(self, msg: str, lineno: int) -> "te.NoReturn":
381
+ """Fail with a :exc:`TemplateAssertionError`."""
382
+ raise TemplateAssertionError(msg, lineno, self.name, self.filename)
383
+
384
+ def temporary_identifier(self) -> str:
385
+ """Get a new unique identifier."""
386
+ self._last_identifier += 1
387
+ return f"t_{self._last_identifier}"
388
+
389
+ def buffer(self, frame: Frame) -> None:
390
+ """Enable buffering for the frame from that point onwards."""
391
+ frame.buffer = self.temporary_identifier()
392
+ self.writeline(f"{frame.buffer} = []")
393
+
394
+ def return_buffer_contents(
395
+ self, frame: Frame, force_unescaped: bool = False
396
+ ) -> None:
397
+ """Return the buffer contents of the frame."""
398
+ if not force_unescaped:
399
+ if frame.eval_ctx.volatile:
400
+ self.writeline("if context.eval_ctx.autoescape:")
401
+ self.indent()
402
+ self.writeline(f"return Markup(concat({frame.buffer}))")
403
+ self.outdent()
404
+ self.writeline("else:")
405
+ self.indent()
406
+ self.writeline(f"return concat({frame.buffer})")
407
+ self.outdent()
408
+ return
409
+ elif frame.eval_ctx.autoescape:
410
+ self.writeline(f"return Markup(concat({frame.buffer}))")
411
+ return
412
+ self.writeline(f"return concat({frame.buffer})")
413
+
414
+ def indent(self) -> None:
415
+ """Indent by one."""
416
+ self._indentation += 1
417
+
418
+ def outdent(self, step: int = 1) -> None:
419
+ """Outdent by step."""
420
+ self._indentation -= step
421
+
422
+ def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None:
423
+ """Yield or write into the frame buffer."""
424
+ if frame.buffer is None:
425
+ self.writeline("yield ", node)
426
+ else:
427
+ self.writeline(f"{frame.buffer}.append(", node)
428
+
429
+ def end_write(self, frame: Frame) -> None:
430
+ """End the writing process started by `start_write`."""
431
+ if frame.buffer is not None:
432
+ self.write(")")
433
+
434
+ def simple_write(
435
+ self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None
436
+ ) -> None:
437
+ """Simple shortcut for start_write + write + end_write."""
438
+ self.start_write(frame, node)
439
+ self.write(s)
440
+ self.end_write(frame)
441
+
442
+ def blockvisit(self, nodes: t.Iterable[nodes.Node], frame: Frame) -> None:
443
+ """Visit a list of nodes as block in a frame. If the current frame
444
+ is no buffer a dummy ``if 0: yield None`` is written automatically.
445
+ """
446
+ try:
447
+ self.writeline("pass")
448
+ for node in nodes:
449
+ self.visit(node, frame)
450
+ except CompilerExit:
451
+ pass
452
+
453
+ def write(self, x: str) -> None:
454
+ """Write a string into the output stream."""
455
+ if self._new_lines:
456
+ if not self._first_write:
457
+ self.stream.write("\n" * self._new_lines)
458
+ self.code_lineno += self._new_lines
459
+ if self._write_debug_info is not None:
460
+ self.debug_info.append((self._write_debug_info, self.code_lineno))
461
+ self._write_debug_info = None
462
+ self._first_write = False
463
+ self.stream.write(" " * self._indentation)
464
+ self._new_lines = 0
465
+ self.stream.write(x)
466
+
467
+ def writeline(
468
+ self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0
469
+ ) -> None:
470
+ """Combination of newline and write."""
471
+ self.newline(node, extra)
472
+ self.write(x)
473
+
474
+ def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None:
475
+ """Add one or more newlines before the next write."""
476
+ self._new_lines = max(self._new_lines, 1 + extra)
477
+ if node is not None and node.lineno != self._last_line:
478
+ self._write_debug_info = node.lineno
479
+ self._last_line = node.lineno
480
+
481
+ def signature(
482
+ self,
483
+ node: t.Union[nodes.Call, nodes.Filter, nodes.Test],
484
+ frame: Frame,
485
+ extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None,
486
+ ) -> None:
487
+ """Writes a function call to the stream for the current node.
488
+ A leading comma is added automatically. The extra keyword
489
+ arguments may not include python keywords otherwise a syntax
490
+ error could occur. The extra keyword arguments should be given
491
+ as python dict.
492
+ """
493
+ # if any of the given keyword arguments is a python keyword
494
+ # we have to make sure that no invalid call is created.
495
+ kwarg_workaround = any(
496
+ is_python_keyword(t.cast(str, k))
497
+ for k in chain((x.key for x in node.kwargs), extra_kwargs or ())
498
+ )
499
+
500
+ for arg in node.args:
501
+ self.write(", ")
502
+ self.visit(arg, frame)
503
+
504
+ if not kwarg_workaround:
505
+ for kwarg in node.kwargs:
506
+ self.write(", ")
507
+ self.visit(kwarg, frame)
508
+ if extra_kwargs is not None:
509
+ for key, value in extra_kwargs.items():
510
+ self.write(f", {key}={value}")
511
+ if node.dyn_args:
512
+ self.write(", *")
513
+ self.visit(node.dyn_args, frame)
514
+
515
+ if kwarg_workaround:
516
+ if node.dyn_kwargs is not None:
517
+ self.write(", **dict({")
518
+ else:
519
+ self.write(", **{")
520
+ for kwarg in node.kwargs:
521
+ self.write(f"{kwarg.key!r}: ")
522
+ self.visit(kwarg.value, frame)
523
+ self.write(", ")
524
+ if extra_kwargs is not None:
525
+ for key, value in extra_kwargs.items():
526
+ self.write(f"{key!r}: {value}, ")
527
+ if node.dyn_kwargs is not None:
528
+ self.write("}, **")
529
+ self.visit(node.dyn_kwargs, frame)
530
+ self.write(")")
531
+ else:
532
+ self.write("}")
533
+
534
+ elif node.dyn_kwargs is not None:
535
+ self.write(", **")
536
+ self.visit(node.dyn_kwargs, frame)
537
+
538
+ def pull_dependencies(self, nodes: t.Iterable[nodes.Node]) -> None:
539
+ """Find all filter and test names used in the template and
540
+ assign them to variables in the compiled namespace. Checking
541
+ that the names are registered with the environment is done when
542
+ compiling the Filter and Test nodes. If the node is in an If or
543
+ CondExpr node, the check is done at runtime instead.
544
+
545
+ .. versionchanged:: 3.0
546
+ Filters and tests in If and CondExpr nodes are checked at
547
+ runtime instead of compile time.
548
+ """
549
+ visitor = DependencyFinderVisitor()
550
+
551
+ for node in nodes:
552
+ visitor.visit(node)
553
+
554
+ for id_map, names, dependency in (
555
+ (self.filters, visitor.filters, "filters"),
556
+ (
557
+ self.tests,
558
+ visitor.tests,
559
+ "tests",
560
+ ),
561
+ ):
562
+ for name in sorted(names):
563
+ if name not in id_map:
564
+ id_map[name] = self.temporary_identifier()
565
+
566
+ # add check during runtime that dependencies used inside of executed
567
+ # blocks are defined, as this step may be skipped during compile time
568
+ self.writeline("try:")
569
+ self.indent()
570
+ self.writeline(f"{id_map[name]} = environment.{dependency}[{name!r}]")
571
+ self.outdent()
572
+ self.writeline("except KeyError:")
573
+ self.indent()
574
+ self.writeline("@internalcode")
575
+ self.writeline(f"def {id_map[name]}(*unused):")
576
+ self.indent()
577
+ self.writeline(
578
+ f'raise TemplateRuntimeError("No {dependency[:-1]}'
579
+ f' named {name!r} found.")'
580
+ )
581
+ self.outdent()
582
+ self.outdent()
583
+
584
+ def enter_frame(self, frame: Frame) -> None:
585
+ undefs = []
586
+ for target, (action, param) in frame.symbols.loads.items():
587
+ if action == VAR_LOAD_PARAMETER:
588
+ pass
589
+ elif action == VAR_LOAD_RESOLVE:
590
+ self.writeline(f"{target} = {self.get_resolve_func()}({param!r})")
591
+ elif action == VAR_LOAD_ALIAS:
592
+ self.writeline(f"{target} = {param}")
593
+ elif action == VAR_LOAD_UNDEFINED:
594
+ undefs.append(target)
595
+ else:
596
+ raise NotImplementedError("unknown load instruction")
597
+ if undefs:
598
+ self.writeline(f"{' = '.join(undefs)} = missing")
599
+
600
+ def leave_frame(self, frame: Frame, with_python_scope: bool = False) -> None:
601
+ if not with_python_scope:
602
+ undefs = []
603
+ for target in frame.symbols.loads:
604
+ undefs.append(target)
605
+ if undefs:
606
+ self.writeline(f"{' = '.join(undefs)} = missing")
607
+
608
+ def choose_async(self, async_value: str = "async ", sync_value: str = "") -> str:
609
+ return async_value if self.environment.is_async else sync_value
610
+
611
+ def func(self, name: str) -> str:
612
+ return f"{self.choose_async()}def {name}"
613
+
614
+ def macro_body(
615
+ self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame
616
+ ) -> t.Tuple[Frame, MacroRef]:
617
+ """Dump the function def of a macro or call block."""
618
+ frame = frame.inner()
619
+ frame.symbols.analyze_node(node)
620
+ macro_ref = MacroRef(node)
621
+
622
+ explicit_caller = None
623
+ skip_special_params = set()
624
+ args = []
625
+
626
+ for idx, arg in enumerate(node.args):
627
+ if arg.name == "caller":
628
+ explicit_caller = idx
629
+ if arg.name in ("kwargs", "varargs"):
630
+ skip_special_params.add(arg.name)
631
+ args.append(frame.symbols.ref(arg.name))
632
+
633
+ undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs"))
634
+
635
+ if "caller" in undeclared:
636
+ # In older Jinja versions there was a bug that allowed caller
637
+ # to retain the special behavior even if it was mentioned in
638
+ # the argument list. However thankfully this was only really
639
+ # working if it was the last argument. So we are explicitly
640
+ # checking this now and error out if it is anywhere else in
641
+ # the argument list.
642
+ if explicit_caller is not None:
643
+ try:
644
+ node.defaults[explicit_caller - len(node.args)]
645
+ except IndexError:
646
+ self.fail(
647
+ "When defining macros or call blocks the "
648
+ 'special "caller" argument must be omitted '
649
+ "or be given a default.",
650
+ node.lineno,
651
+ )
652
+ else:
653
+ args.append(frame.symbols.declare_parameter("caller"))
654
+ macro_ref.accesses_caller = True
655
+ if "kwargs" in undeclared and "kwargs" not in skip_special_params:
656
+ args.append(frame.symbols.declare_parameter("kwargs"))
657
+ macro_ref.accesses_kwargs = True
658
+ if "varargs" in undeclared and "varargs" not in skip_special_params:
659
+ args.append(frame.symbols.declare_parameter("varargs"))
660
+ macro_ref.accesses_varargs = True
661
+
662
+ # macros are delayed, they never require output checks
663
+ frame.require_output_check = False
664
+ frame.symbols.analyze_node(node)
665
+ self.writeline(f"{self.func('macro')}({', '.join(args)}):", node)
666
+ self.indent()
667
+
668
+ self.buffer(frame)
669
+ self.enter_frame(frame)
670
+
671
+ self.push_parameter_definitions(frame)
672
+ for idx, arg in enumerate(node.args):
673
+ ref = frame.symbols.ref(arg.name)
674
+ self.writeline(f"if {ref} is missing:")
675
+ self.indent()
676
+ try:
677
+ default = node.defaults[idx - len(node.args)]
678
+ except IndexError:
679
+ self.writeline(
680
+ f'{ref} = undefined("parameter {arg.name!r} was not provided",'
681
+ f" name={arg.name!r})"
682
+ )
683
+ else:
684
+ self.writeline(f"{ref} = ")
685
+ self.visit(default, frame)
686
+ self.mark_parameter_stored(ref)
687
+ self.outdent()
688
+ self.pop_parameter_definitions()
689
+
690
+ self.blockvisit(node.body, frame)
691
+ self.return_buffer_contents(frame, force_unescaped=True)
692
+ self.leave_frame(frame, with_python_scope=True)
693
+ self.outdent()
694
+
695
+ return frame, macro_ref
696
+
697
+ def macro_def(self, macro_ref: MacroRef, frame: Frame) -> None:
698
+ """Dump the macro definition for the def created by macro_body."""
699
+ arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args)
700
+ name = getattr(macro_ref.node, "name", None)
701
+ if len(macro_ref.node.args) == 1:
702
+ arg_tuple += ","
703
+ self.write(
704
+ f"Macro(environment, macro, {name!r}, ({arg_tuple}),"
705
+ f" {macro_ref.accesses_kwargs!r}, {macro_ref.accesses_varargs!r},"
706
+ f" {macro_ref.accesses_caller!r}, context.eval_ctx.autoescape)"
707
+ )
708
+
709
+ def position(self, node: nodes.Node) -> str:
710
+ """Return a human readable position for the node."""
711
+ rv = f"line {node.lineno}"
712
+ if self.name is not None:
713
+ rv = f"{rv} in {self.name!r}"
714
+ return rv
715
+
716
+ def dump_local_context(self, frame: Frame) -> str:
717
+ items_kv = ", ".join(
718
+ f"{name!r}: {target}"
719
+ for name, target in frame.symbols.dump_stores().items()
720
+ )
721
+ return f"{{{items_kv}}}"
722
+
723
+ def write_commons(self) -> None:
724
+ """Writes a common preamble that is used by root and block functions.
725
+ Primarily this sets up common local helpers and enforces a generator
726
+ through a dead branch.
727
+ """
728
+ self.writeline("resolve = context.resolve_or_missing")
729
+ self.writeline("undefined = environment.undefined")
730
+ self.writeline("concat = environment.concat")
731
+ # always use the standard Undefined class for the implicit else of
732
+ # conditional expressions
733
+ self.writeline("cond_expr_undefined = Undefined")
734
+ self.writeline("if 0: yield None")
735
+
736
+ def push_parameter_definitions(self, frame: Frame) -> None:
737
+ """Pushes all parameter targets from the given frame into a local
738
+ stack that permits tracking of yet to be assigned parameters. In
739
+ particular this enables the optimization from `visit_Name` to skip
740
+ undefined expressions for parameters in macros as macros can reference
741
+ otherwise unbound parameters.
742
+ """
743
+ self._param_def_block.append(frame.symbols.dump_param_targets())
744
+
745
+ def pop_parameter_definitions(self) -> None:
746
+ """Pops the current parameter definitions set."""
747
+ self._param_def_block.pop()
748
+
749
+ def mark_parameter_stored(self, target: str) -> None:
750
+ """Marks a parameter in the current parameter definitions as stored.
751
+ This will skip the enforced undefined checks.
752
+ """
753
+ if self._param_def_block:
754
+ self._param_def_block[-1].discard(target)
755
+
756
+ def push_context_reference(self, target: str) -> None:
757
+ self._context_reference_stack.append(target)
758
+
759
+ def pop_context_reference(self) -> None:
760
+ self._context_reference_stack.pop()
761
+
762
+ def get_context_ref(self) -> str:
763
+ return self._context_reference_stack[-1]
764
+
765
+ def get_resolve_func(self) -> str:
766
+ target = self._context_reference_stack[-1]
767
+ if target == "context":
768
+ return "resolve"
769
+ return f"{target}.resolve"
770
+
771
+ def derive_context(self, frame: Frame) -> str:
772
+ return f"{self.get_context_ref()}.derived({self.dump_local_context(frame)})"
773
+
774
+ def parameter_is_undeclared(self, target: str) -> bool:
775
+ """Checks if a given target is an undeclared parameter."""
776
+ if not self._param_def_block:
777
+ return False
778
+ return target in self._param_def_block[-1]
779
+
780
+ def push_assign_tracking(self) -> None:
781
+ """Pushes a new layer for assignment tracking."""
782
+ self._assign_stack.append(set())
783
+
784
+ def pop_assign_tracking(self, frame: Frame) -> None:
785
+ """Pops the topmost level for assignment tracking and updates the
786
+ context variables if necessary.
787
+ """
788
+ vars = self._assign_stack.pop()
789
+ if (
790
+ not frame.block_frame
791
+ and not frame.loop_frame
792
+ and not frame.toplevel
793
+ or not vars
794
+ ):
795
+ return
796
+ public_names = [x for x in vars if x[:1] != "_"]
797
+ if len(vars) == 1:
798
+ name = next(iter(vars))
799
+ ref = frame.symbols.ref(name)
800
+ if frame.loop_frame:
801
+ self.writeline(f"_loop_vars[{name!r}] = {ref}")
802
+ return
803
+ if frame.block_frame:
804
+ self.writeline(f"_block_vars[{name!r}] = {ref}")
805
+ return
806
+ self.writeline(f"context.vars[{name!r}] = {ref}")
807
+ else:
808
+ if frame.loop_frame:
809
+ self.writeline("_loop_vars.update({")
810
+ elif frame.block_frame:
811
+ self.writeline("_block_vars.update({")
812
+ else:
813
+ self.writeline("context.vars.update({")
814
+ for idx, name in enumerate(sorted(vars)):
815
+ if idx:
816
+ self.write(", ")
817
+ ref = frame.symbols.ref(name)
818
+ self.write(f"{name!r}: {ref}")
819
+ self.write("})")
820
+ if not frame.block_frame and not frame.loop_frame and public_names:
821
+ if len(public_names) == 1:
822
+ self.writeline(f"context.exported_vars.add({public_names[0]!r})")
823
+ else:
824
+ names_str = ", ".join(map(repr, sorted(public_names)))
825
+ self.writeline(f"context.exported_vars.update(({names_str}))")
826
+
827
+ # -- Statement Visitors
828
+
829
+ def visit_Template(
830
+ self, node: nodes.Template, frame: t.Optional[Frame] = None
831
+ ) -> None:
832
+ assert frame is None, "no root frame allowed"
833
+ eval_ctx = EvalContext(self.environment, self.name)
834
+
835
+ from .runtime import async_exported
836
+ from .runtime import exported
837
+
838
+ if self.environment.is_async:
839
+ exported_names = sorted(exported + async_exported)
840
+ else:
841
+ exported_names = sorted(exported)
842
+
843
+ self.writeline("from jinja2.runtime import " + ", ".join(exported_names))
844
+
845
+ # if we want a deferred initialization we cannot move the
846
+ # environment into a local name
847
+ envenv = "" if self.defer_init else ", environment=environment"
848
+
849
+ # do we have an extends tag at all? If not, we can save some
850
+ # overhead by just not processing any inheritance code.
851
+ have_extends = node.find(nodes.Extends) is not None
852
+
853
+ # find all blocks
854
+ for block in node.find_all(nodes.Block):
855
+ if block.name in self.blocks:
856
+ self.fail(f"block {block.name!r} defined twice", block.lineno)
857
+ self.blocks[block.name] = block
858
+
859
+ # find all imports and import them
860
+ for import_ in node.find_all(nodes.ImportedName):
861
+ if import_.importname not in self.import_aliases:
862
+ imp = import_.importname
863
+ self.import_aliases[imp] = alias = self.temporary_identifier()
864
+ if "." in imp:
865
+ module, obj = imp.rsplit(".", 1)
866
+ self.writeline(f"from {module} import {obj} as {alias}")
867
+ else:
868
+ self.writeline(f"import {imp} as {alias}")
869
+
870
+ # add the load name
871
+ self.writeline(f"name = {self.name!r}")
872
+
873
+ # generate the root render function.
874
+ self.writeline(
875
+ f"{self.func('root')}(context, missing=missing{envenv}):", extra=1
876
+ )
877
+ self.indent()
878
+ self.write_commons()
879
+
880
+ # process the root
881
+ frame = Frame(eval_ctx)
882
+ if "self" in find_undeclared(node.body, ("self",)):
883
+ ref = frame.symbols.declare_parameter("self")
884
+ self.writeline(f"{ref} = TemplateReference(context)")
885
+ frame.symbols.analyze_node(node)
886
+ frame.toplevel = frame.rootlevel = True
887
+ frame.require_output_check = have_extends and not self.has_known_extends
888
+ if have_extends:
889
+ self.writeline("parent_template = None")
890
+ self.enter_frame(frame)
891
+ self.pull_dependencies(node.body)
892
+ self.blockvisit(node.body, frame)
893
+ self.leave_frame(frame, with_python_scope=True)
894
+ self.outdent()
895
+
896
+ # make sure that the parent root is called.
897
+ if have_extends:
898
+ if not self.has_known_extends:
899
+ self.indent()
900
+ self.writeline("if parent_template is not None:")
901
+ self.indent()
902
+ if not self.environment.is_async:
903
+ self.writeline("yield from parent_template.root_render_func(context)")
904
+ else:
905
+ self.writeline("agen = parent_template.root_render_func(context)")
906
+ self.writeline("try:")
907
+ self.indent()
908
+ self.writeline("async for event in agen:")
909
+ self.indent()
910
+ self.writeline("yield event")
911
+ self.outdent()
912
+ self.outdent()
913
+ self.writeline("finally: await agen.aclose()")
914
+ self.outdent(1 + (not self.has_known_extends))
915
+
916
+ # at this point we now have the blocks collected and can visit them too.
917
+ for name, block in self.blocks.items():
918
+ self.writeline(
919
+ f"{self.func('block_' + name)}(context, missing=missing{envenv}):",
920
+ block,
921
+ 1,
922
+ )
923
+ self.indent()
924
+ self.write_commons()
925
+ # It's important that we do not make this frame a child of the
926
+ # toplevel template. This would cause a variety of
927
+ # interesting issues with identifier tracking.
928
+ block_frame = Frame(eval_ctx)
929
+ block_frame.block_frame = True
930
+ undeclared = find_undeclared(block.body, ("self", "super"))
931
+ if "self" in undeclared:
932
+ ref = block_frame.symbols.declare_parameter("self")
933
+ self.writeline(f"{ref} = TemplateReference(context)")
934
+ if "super" in undeclared:
935
+ ref = block_frame.symbols.declare_parameter("super")
936
+ self.writeline(f"{ref} = context.super({name!r}, block_{name})")
937
+ block_frame.symbols.analyze_node(block)
938
+ block_frame.block = name
939
+ self.writeline("_block_vars = {}")
940
+ self.enter_frame(block_frame)
941
+ self.pull_dependencies(block.body)
942
+ self.blockvisit(block.body, block_frame)
943
+ self.leave_frame(block_frame, with_python_scope=True)
944
+ self.outdent()
945
+
946
+ blocks_kv_str = ", ".join(f"{x!r}: block_{x}" for x in self.blocks)
947
+ self.writeline(f"blocks = {{{blocks_kv_str}}}", extra=1)
948
+ debug_kv_str = "&".join(f"{k}={v}" for k, v in self.debug_info)
949
+ self.writeline(f"debug_info = {debug_kv_str!r}")
950
+
951
+ def visit_Block(self, node: nodes.Block, frame: Frame) -> None:
952
+ """Call a block and register it for the template."""
953
+ level = 0
954
+ if frame.toplevel:
955
+ # if we know that we are a child template, there is no need to
956
+ # check if we are one
957
+ if self.has_known_extends:
958
+ return
959
+ if self.extends_so_far > 0:
960
+ self.writeline("if parent_template is None:")
961
+ self.indent()
962
+ level += 1
963
+
964
+ if node.scoped:
965
+ context = self.derive_context(frame)
966
+ else:
967
+ context = self.get_context_ref()
968
+
969
+ if node.required:
970
+ self.writeline(f"if len(context.blocks[{node.name!r}]) <= 1:", node)
971
+ self.indent()
972
+ self.writeline(
973
+ f'raise TemplateRuntimeError("Required block {node.name!r} not found")',
974
+ node,
975
+ )
976
+ self.outdent()
977
+
978
+ if not self.environment.is_async and frame.buffer is None:
979
+ self.writeline(
980
+ f"yield from context.blocks[{node.name!r}][0]({context})", node
981
+ )
982
+ else:
983
+ self.writeline(f"gen = context.blocks[{node.name!r}][0]({context})")
984
+ self.writeline("try:")
985
+ self.indent()
986
+ self.writeline(
987
+ f"{self.choose_async()}for event in gen:",
988
+ node,
989
+ )
990
+ self.indent()
991
+ self.simple_write("event", frame)
992
+ self.outdent()
993
+ self.outdent()
994
+ self.writeline(
995
+ f"finally: {self.choose_async('await gen.aclose()', 'gen.close()')}"
996
+ )
997
+
998
+ self.outdent(level)
999
+
1000
+ def visit_Extends(self, node: nodes.Extends, frame: Frame) -> None:
1001
+ """Calls the extender."""
1002
+ if not frame.toplevel:
1003
+ self.fail("cannot use extend from a non top-level scope", node.lineno)
1004
+
1005
+ # if the number of extends statements in general is zero so
1006
+ # far, we don't have to add a check if something extended
1007
+ # the template before this one.
1008
+ if self.extends_so_far > 0:
1009
+ # if we have a known extends we just add a template runtime
1010
+ # error into the generated code. We could catch that at compile
1011
+ # time too, but i welcome it not to confuse users by throwing the
1012
+ # same error at different times just "because we can".
1013
+ if not self.has_known_extends:
1014
+ self.writeline("if parent_template is not None:")
1015
+ self.indent()
1016
+ self.writeline('raise TemplateRuntimeError("extended multiple times")')
1017
+
1018
+ # if we have a known extends already we don't need that code here
1019
+ # as we know that the template execution will end here.
1020
+ if self.has_known_extends:
1021
+ raise CompilerExit()
1022
+ else:
1023
+ self.outdent()
1024
+
1025
+ self.writeline("parent_template = environment.get_template(", node)
1026
+ self.visit(node.template, frame)
1027
+ self.write(f", {self.name!r})")
1028
+ self.writeline("for name, parent_block in parent_template.blocks.items():")
1029
+ self.indent()
1030
+ self.writeline("context.blocks.setdefault(name, []).append(parent_block)")
1031
+ self.outdent()
1032
+
1033
+ # if this extends statement was in the root level we can take
1034
+ # advantage of that information and simplify the generated code
1035
+ # in the top level from this point onwards
1036
+ if frame.rootlevel:
1037
+ self.has_known_extends = True
1038
+
1039
+ # and now we have one more
1040
+ self.extends_so_far += 1
1041
+
1042
+ def visit_Include(self, node: nodes.Include, frame: Frame) -> None:
1043
+ """Handles includes."""
1044
+ if node.ignore_missing:
1045
+ self.writeline("try:")
1046
+ self.indent()
1047
+
1048
+ func_name = "get_or_select_template"
1049
+ if isinstance(node.template, nodes.Const):
1050
+ if isinstance(node.template.value, str):
1051
+ func_name = "get_template"
1052
+ elif isinstance(node.template.value, (tuple, list)):
1053
+ func_name = "select_template"
1054
+ elif isinstance(node.template, (nodes.Tuple, nodes.List)):
1055
+ func_name = "select_template"
1056
+
1057
+ self.writeline(f"template = environment.{func_name}(", node)
1058
+ self.visit(node.template, frame)
1059
+ self.write(f", {self.name!r})")
1060
+ if node.ignore_missing:
1061
+ self.outdent()
1062
+ self.writeline("except TemplateNotFound:")
1063
+ self.indent()
1064
+ self.writeline("pass")
1065
+ self.outdent()
1066
+ self.writeline("else:")
1067
+ self.indent()
1068
+
1069
+ def loop_body() -> None:
1070
+ self.indent()
1071
+ self.simple_write("event", frame)
1072
+ self.outdent()
1073
+
1074
+ if node.with_context:
1075
+ self.writeline(
1076
+ f"gen = template.root_render_func("
1077
+ "template.new_context(context.get_all(), True,"
1078
+ f" {self.dump_local_context(frame)}))"
1079
+ )
1080
+ self.writeline("try:")
1081
+ self.indent()
1082
+ self.writeline(f"{self.choose_async()}for event in gen:")
1083
+ loop_body()
1084
+ self.outdent()
1085
+ self.writeline(
1086
+ f"finally: {self.choose_async('await gen.aclose()', 'gen.close()')}"
1087
+ )
1088
+ elif self.environment.is_async:
1089
+ self.writeline(
1090
+ "for event in (await template._get_default_module_async())"
1091
+ "._body_stream:"
1092
+ )
1093
+ loop_body()
1094
+ else:
1095
+ self.writeline("yield from template._get_default_module()._body_stream")
1096
+
1097
+ if node.ignore_missing:
1098
+ self.outdent()
1099
+
1100
+ def _import_common(
1101
+ self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame
1102
+ ) -> None:
1103
+ self.write(f"{self.choose_async('await ')}environment.get_template(")
1104
+ self.visit(node.template, frame)
1105
+ self.write(f", {self.name!r}).")
1106
+
1107
+ if node.with_context:
1108
+ f_name = f"make_module{self.choose_async('_async')}"
1109
+ self.write(
1110
+ f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})"
1111
+ )
1112
+ else:
1113
+ self.write(f"_get_default_module{self.choose_async('_async')}(context)")
1114
+
1115
+ def visit_Import(self, node: nodes.Import, frame: Frame) -> None:
1116
+ """Visit regular imports."""
1117
+ self.writeline(f"{frame.symbols.ref(node.target)} = ", node)
1118
+ if frame.toplevel:
1119
+ self.write(f"context.vars[{node.target!r}] = ")
1120
+
1121
+ self._import_common(node, frame)
1122
+
1123
+ if frame.toplevel and not node.target.startswith("_"):
1124
+ self.writeline(f"context.exported_vars.discard({node.target!r})")
1125
+
1126
+ def visit_FromImport(self, node: nodes.FromImport, frame: Frame) -> None:
1127
+ """Visit named imports."""
1128
+ self.newline(node)
1129
+ self.write("included_template = ")
1130
+ self._import_common(node, frame)
1131
+ var_names = []
1132
+ discarded_names = []
1133
+ for name in node.names:
1134
+ if isinstance(name, tuple):
1135
+ name, alias = name
1136
+ else:
1137
+ alias = name
1138
+ self.writeline(
1139
+ f"{frame.symbols.ref(alias)} ="
1140
+ f" getattr(included_template, {name!r}, missing)"
1141
+ )
1142
+ self.writeline(f"if {frame.symbols.ref(alias)} is missing:")
1143
+ self.indent()
1144
+ # The position will contain the template name, and will be formatted
1145
+ # into a string that will be compiled into an f-string. Curly braces
1146
+ # in the name must be replaced with escapes so that they will not be
1147
+ # executed as part of the f-string.
1148
+ position = self.position(node).replace("{", "{{").replace("}", "}}")
1149
+ message = (
1150
+ "the template {included_template.__name__!r}"
1151
+ f" (imported on {position})"
1152
+ f" does not export the requested name {name!r}"
1153
+ )
1154
+ self.writeline(
1155
+ f"{frame.symbols.ref(alias)} = undefined(f{message!r}, name={name!r})"
1156
+ )
1157
+ self.outdent()
1158
+ if frame.toplevel:
1159
+ var_names.append(alias)
1160
+ if not alias.startswith("_"):
1161
+ discarded_names.append(alias)
1162
+
1163
+ if var_names:
1164
+ if len(var_names) == 1:
1165
+ name = var_names[0]
1166
+ self.writeline(f"context.vars[{name!r}] = {frame.symbols.ref(name)}")
1167
+ else:
1168
+ names_kv = ", ".join(
1169
+ f"{name!r}: {frame.symbols.ref(name)}" for name in var_names
1170
+ )
1171
+ self.writeline(f"context.vars.update({{{names_kv}}})")
1172
+ if discarded_names:
1173
+ if len(discarded_names) == 1:
1174
+ self.writeline(f"context.exported_vars.discard({discarded_names[0]!r})")
1175
+ else:
1176
+ names_str = ", ".join(map(repr, discarded_names))
1177
+ self.writeline(
1178
+ f"context.exported_vars.difference_update(({names_str}))"
1179
+ )
1180
+
1181
+ def visit_For(self, node: nodes.For, frame: Frame) -> None:
1182
+ loop_frame = frame.inner()
1183
+ loop_frame.loop_frame = True
1184
+ test_frame = frame.inner()
1185
+ else_frame = frame.inner()
1186
+
1187
+ # try to figure out if we have an extended loop. An extended loop
1188
+ # is necessary if the loop is in recursive mode if the special loop
1189
+ # variable is accessed in the body if the body is a scoped block.
1190
+ extended_loop = (
1191
+ node.recursive
1192
+ or "loop"
1193
+ in find_undeclared(node.iter_child_nodes(only=("body",)), ("loop",))
1194
+ or any(block.scoped for block in node.find_all(nodes.Block))
1195
+ )
1196
+
1197
+ loop_ref = None
1198
+ if extended_loop:
1199
+ loop_ref = loop_frame.symbols.declare_parameter("loop")
1200
+
1201
+ loop_frame.symbols.analyze_node(node, for_branch="body")
1202
+ if node.else_:
1203
+ else_frame.symbols.analyze_node(node, for_branch="else")
1204
+
1205
+ if node.test:
1206
+ loop_filter_func = self.temporary_identifier()
1207
+ test_frame.symbols.analyze_node(node, for_branch="test")
1208
+ self.writeline(f"{self.func(loop_filter_func)}(fiter):", node.test)
1209
+ self.indent()
1210
+ self.enter_frame(test_frame)
1211
+ self.writeline(self.choose_async("async for ", "for "))
1212
+ self.visit(node.target, loop_frame)
1213
+ self.write(" in ")
1214
+ self.write(self.choose_async("auto_aiter(fiter)", "fiter"))
1215
+ self.write(":")
1216
+ self.indent()
1217
+ self.writeline("if ", node.test)
1218
+ self.visit(node.test, test_frame)
1219
+ self.write(":")
1220
+ self.indent()
1221
+ self.writeline("yield ")
1222
+ self.visit(node.target, loop_frame)
1223
+ self.outdent(3)
1224
+ self.leave_frame(test_frame, with_python_scope=True)
1225
+
1226
+ # if we don't have an recursive loop we have to find the shadowed
1227
+ # variables at that point. Because loops can be nested but the loop
1228
+ # variable is a special one we have to enforce aliasing for it.
1229
+ if node.recursive:
1230
+ self.writeline(
1231
+ f"{self.func('loop')}(reciter, loop_render_func, depth=0):", node
1232
+ )
1233
+ self.indent()
1234
+ self.buffer(loop_frame)
1235
+
1236
+ # Use the same buffer for the else frame
1237
+ else_frame.buffer = loop_frame.buffer
1238
+
1239
+ # make sure the loop variable is a special one and raise a template
1240
+ # assertion error if a loop tries to write to loop
1241
+ if extended_loop:
1242
+ self.writeline(f"{loop_ref} = missing")
1243
+
1244
+ for name in node.find_all(nodes.Name):
1245
+ if name.ctx == "store" and name.name == "loop":
1246
+ self.fail(
1247
+ "Can't assign to special loop variable in for-loop target",
1248
+ name.lineno,
1249
+ )
1250
+
1251
+ if node.else_:
1252
+ iteration_indicator = self.temporary_identifier()
1253
+ self.writeline(f"{iteration_indicator} = 1")
1254
+
1255
+ self.writeline(self.choose_async("async for ", "for "), node)
1256
+ self.visit(node.target, loop_frame)
1257
+ if extended_loop:
1258
+ self.write(f", {loop_ref} in {self.choose_async('Async')}LoopContext(")
1259
+ else:
1260
+ self.write(" in ")
1261
+
1262
+ if node.test:
1263
+ self.write(f"{loop_filter_func}(")
1264
+ if node.recursive:
1265
+ self.write("reciter")
1266
+ else:
1267
+ if self.environment.is_async and not extended_loop:
1268
+ self.write("auto_aiter(")
1269
+ self.visit(node.iter, frame)
1270
+ if self.environment.is_async and not extended_loop:
1271
+ self.write(")")
1272
+ if node.test:
1273
+ self.write(")")
1274
+
1275
+ if node.recursive:
1276
+ self.write(", undefined, loop_render_func, depth):")
1277
+ else:
1278
+ self.write(", undefined):" if extended_loop else ":")
1279
+
1280
+ self.indent()
1281
+ self.enter_frame(loop_frame)
1282
+
1283
+ self.writeline("_loop_vars = {}")
1284
+ self.blockvisit(node.body, loop_frame)
1285
+ if node.else_:
1286
+ self.writeline(f"{iteration_indicator} = 0")
1287
+ self.outdent()
1288
+ self.leave_frame(
1289
+ loop_frame, with_python_scope=node.recursive and not node.else_
1290
+ )
1291
+
1292
+ if node.else_:
1293
+ self.writeline(f"if {iteration_indicator}:")
1294
+ self.indent()
1295
+ self.enter_frame(else_frame)
1296
+ self.blockvisit(node.else_, else_frame)
1297
+ self.leave_frame(else_frame)
1298
+ self.outdent()
1299
+
1300
+ # if the node was recursive we have to return the buffer contents
1301
+ # and start the iteration code
1302
+ if node.recursive:
1303
+ self.return_buffer_contents(loop_frame)
1304
+ self.outdent()
1305
+ self.start_write(frame, node)
1306
+ self.write(f"{self.choose_async('await ')}loop(")
1307
+ if self.environment.is_async:
1308
+ self.write("auto_aiter(")
1309
+ self.visit(node.iter, frame)
1310
+ if self.environment.is_async:
1311
+ self.write(")")
1312
+ self.write(", loop)")
1313
+ self.end_write(frame)
1314
+
1315
+ # at the end of the iteration, clear any assignments made in the
1316
+ # loop from the top level
1317
+ if self._assign_stack:
1318
+ self._assign_stack[-1].difference_update(loop_frame.symbols.stores)
1319
+
1320
+ def visit_If(self, node: nodes.If, frame: Frame) -> None:
1321
+ if_frame = frame.soft()
1322
+ self.writeline("if ", node)
1323
+ self.visit(node.test, if_frame)
1324
+ self.write(":")
1325
+ self.indent()
1326
+ self.blockvisit(node.body, if_frame)
1327
+ self.outdent()
1328
+ for elif_ in node.elif_:
1329
+ self.writeline("elif ", elif_)
1330
+ self.visit(elif_.test, if_frame)
1331
+ self.write(":")
1332
+ self.indent()
1333
+ self.blockvisit(elif_.body, if_frame)
1334
+ self.outdent()
1335
+ if node.else_:
1336
+ self.writeline("else:")
1337
+ self.indent()
1338
+ self.blockvisit(node.else_, if_frame)
1339
+ self.outdent()
1340
+
1341
+ def visit_Macro(self, node: nodes.Macro, frame: Frame) -> None:
1342
+ macro_frame, macro_ref = self.macro_body(node, frame)
1343
+ self.newline()
1344
+ if frame.toplevel:
1345
+ if not node.name.startswith("_"):
1346
+ self.write(f"context.exported_vars.add({node.name!r})")
1347
+ self.writeline(f"context.vars[{node.name!r}] = ")
1348
+ self.write(f"{frame.symbols.ref(node.name)} = ")
1349
+ self.macro_def(macro_ref, macro_frame)
1350
+
1351
+ def visit_CallBlock(self, node: nodes.CallBlock, frame: Frame) -> None:
1352
+ call_frame, macro_ref = self.macro_body(node, frame)
1353
+ self.writeline("caller = ")
1354
+ self.macro_def(macro_ref, call_frame)
1355
+ self.start_write(frame, node)
1356
+ self.visit_Call(node.call, frame, forward_caller=True)
1357
+ self.end_write(frame)
1358
+
1359
+ def visit_FilterBlock(self, node: nodes.FilterBlock, frame: Frame) -> None:
1360
+ filter_frame = frame.inner()
1361
+ filter_frame.symbols.analyze_node(node)
1362
+ self.enter_frame(filter_frame)
1363
+ self.buffer(filter_frame)
1364
+ self.blockvisit(node.body, filter_frame)
1365
+ self.start_write(frame, node)
1366
+ self.visit_Filter(node.filter, filter_frame)
1367
+ self.end_write(frame)
1368
+ self.leave_frame(filter_frame)
1369
+
1370
+ def visit_With(self, node: nodes.With, frame: Frame) -> None:
1371
+ with_frame = frame.inner()
1372
+ with_frame.symbols.analyze_node(node)
1373
+ self.enter_frame(with_frame)
1374
+ for target, expr in zip(node.targets, node.values):
1375
+ self.newline()
1376
+ self.visit(target, with_frame)
1377
+ self.write(" = ")
1378
+ self.visit(expr, frame)
1379
+ self.blockvisit(node.body, with_frame)
1380
+ self.leave_frame(with_frame)
1381
+
1382
+ def visit_ExprStmt(self, node: nodes.ExprStmt, frame: Frame) -> None:
1383
+ self.newline(node)
1384
+ self.visit(node.node, frame)
1385
+
1386
+ class _FinalizeInfo(t.NamedTuple):
1387
+ const: t.Optional[t.Callable[..., str]]
1388
+ src: t.Optional[str]
1389
+
1390
+ @staticmethod
1391
+ def _default_finalize(value: t.Any) -> t.Any:
1392
+ """The default finalize function if the environment isn't
1393
+ configured with one. Or, if the environment has one, this is
1394
+ called on that function's output for constants.
1395
+ """
1396
+ return str(value)
1397
+
1398
+ _finalize: t.Optional[_FinalizeInfo] = None
1399
+
1400
+ def _make_finalize(self) -> _FinalizeInfo:
1401
+ """Build the finalize function to be used on constants and at
1402
+ runtime. Cached so it's only created once for all output nodes.
1403
+
1404
+ Returns a ``namedtuple`` with the following attributes:
1405
+
1406
+ ``const``
1407
+ A function to finalize constant data at compile time.
1408
+
1409
+ ``src``
1410
+ Source code to output around nodes to be evaluated at
1411
+ runtime.
1412
+ """
1413
+ if self._finalize is not None:
1414
+ return self._finalize
1415
+
1416
+ finalize: t.Optional[t.Callable[..., t.Any]]
1417
+ finalize = default = self._default_finalize
1418
+ src = None
1419
+
1420
+ if self.environment.finalize:
1421
+ src = "environment.finalize("
1422
+ env_finalize = self.environment.finalize
1423
+ pass_arg = {
1424
+ _PassArg.context: "context",
1425
+ _PassArg.eval_context: "context.eval_ctx",
1426
+ _PassArg.environment: "environment",
1427
+ }.get(
1428
+ _PassArg.from_obj(env_finalize) # type: ignore
1429
+ )
1430
+ finalize = None
1431
+
1432
+ if pass_arg is None:
1433
+
1434
+ def finalize(value: t.Any) -> t.Any: # noqa: F811
1435
+ return default(env_finalize(value))
1436
+
1437
+ else:
1438
+ src = f"{src}{pass_arg}, "
1439
+
1440
+ if pass_arg == "environment":
1441
+
1442
+ def finalize(value: t.Any) -> t.Any: # noqa: F811
1443
+ return default(env_finalize(self.environment, value))
1444
+
1445
+ self._finalize = self._FinalizeInfo(finalize, src)
1446
+ return self._finalize
1447
+
1448
+ def _output_const_repr(self, group: t.Iterable[t.Any]) -> str:
1449
+ """Given a group of constant values converted from ``Output``
1450
+ child nodes, produce a string to write to the template module
1451
+ source.
1452
+ """
1453
+ return repr(concat(group))
1454
+
1455
+ def _output_child_to_const(
1456
+ self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo
1457
+ ) -> str:
1458
+ """Try to optimize a child of an ``Output`` node by trying to
1459
+ convert it to constant, finalized data at compile time.
1460
+
1461
+ If :exc:`Impossible` is raised, the node is not constant and
1462
+ will be evaluated at runtime. Any other exception will also be
1463
+ evaluated at runtime for easier debugging.
1464
+ """
1465
+ const = node.as_const(frame.eval_ctx)
1466
+
1467
+ if frame.eval_ctx.autoescape:
1468
+ const = escape(const)
1469
+
1470
+ # Template data doesn't go through finalize.
1471
+ if isinstance(node, nodes.TemplateData):
1472
+ return str(const)
1473
+
1474
+ return finalize.const(const) # type: ignore
1475
+
1476
+ def _output_child_pre(
1477
+ self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo
1478
+ ) -> None:
1479
+ """Output extra source code before visiting a child of an
1480
+ ``Output`` node.
1481
+ """
1482
+ if frame.eval_ctx.volatile:
1483
+ self.write("(escape if context.eval_ctx.autoescape else str)(")
1484
+ elif frame.eval_ctx.autoescape:
1485
+ self.write("escape(")
1486
+ else:
1487
+ self.write("str(")
1488
+
1489
+ if finalize.src is not None:
1490
+ self.write(finalize.src)
1491
+
1492
+ def _output_child_post(
1493
+ self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo
1494
+ ) -> None:
1495
+ """Output extra source code after visiting a child of an
1496
+ ``Output`` node.
1497
+ """
1498
+ self.write(")")
1499
+
1500
+ if finalize.src is not None:
1501
+ self.write(")")
1502
+
1503
+ def visit_Output(self, node: nodes.Output, frame: Frame) -> None:
1504
+ # If an extends is active, don't render outside a block.
1505
+ if frame.require_output_check:
1506
+ # A top-level extends is known to exist at compile time.
1507
+ if self.has_known_extends:
1508
+ return
1509
+
1510
+ self.writeline("if parent_template is None:")
1511
+ self.indent()
1512
+
1513
+ finalize = self._make_finalize()
1514
+ body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = []
1515
+
1516
+ # Evaluate constants at compile time if possible. Each item in
1517
+ # body will be either a list of static data or a node to be
1518
+ # evaluated at runtime.
1519
+ for child in node.nodes:
1520
+ try:
1521
+ if not (
1522
+ # If the finalize function requires runtime context,
1523
+ # constants can't be evaluated at compile time.
1524
+ finalize.const
1525
+ # Unless it's basic template data that won't be
1526
+ # finalized anyway.
1527
+ or isinstance(child, nodes.TemplateData)
1528
+ ):
1529
+ raise nodes.Impossible()
1530
+
1531
+ const = self._output_child_to_const(child, frame, finalize)
1532
+ except (nodes.Impossible, Exception):
1533
+ # The node was not constant and needs to be evaluated at
1534
+ # runtime. Or another error was raised, which is easier
1535
+ # to debug at runtime.
1536
+ body.append(child)
1537
+ continue
1538
+
1539
+ if body and isinstance(body[-1], list):
1540
+ body[-1].append(const)
1541
+ else:
1542
+ body.append([const])
1543
+
1544
+ if frame.buffer is not None:
1545
+ if len(body) == 1:
1546
+ self.writeline(f"{frame.buffer}.append(")
1547
+ else:
1548
+ self.writeline(f"{frame.buffer}.extend((")
1549
+
1550
+ self.indent()
1551
+
1552
+ for item in body:
1553
+ if isinstance(item, list):
1554
+ # A group of constant data to join and output.
1555
+ val = self._output_const_repr(item)
1556
+
1557
+ if frame.buffer is None:
1558
+ self.writeline("yield " + val)
1559
+ else:
1560
+ self.writeline(val + ",")
1561
+ else:
1562
+ if frame.buffer is None:
1563
+ self.writeline("yield ", item)
1564
+ else:
1565
+ self.newline(item)
1566
+
1567
+ # A node to be evaluated at runtime.
1568
+ self._output_child_pre(item, frame, finalize)
1569
+ self.visit(item, frame)
1570
+ self._output_child_post(item, frame, finalize)
1571
+
1572
+ if frame.buffer is not None:
1573
+ self.write(",")
1574
+
1575
+ if frame.buffer is not None:
1576
+ self.outdent()
1577
+ self.writeline(")" if len(body) == 1 else "))")
1578
+
1579
+ if frame.require_output_check:
1580
+ self.outdent()
1581
+
1582
+ def visit_Assign(self, node: nodes.Assign, frame: Frame) -> None:
1583
+ self.push_assign_tracking()
1584
+
1585
+ # ``a.b`` is allowed for assignment, and is parsed as an NSRef. However,
1586
+ # it is only valid if it references a Namespace object. Emit a check for
1587
+ # that for each ref here, before assignment code is emitted. This can't
1588
+ # be done in visit_NSRef as the ref could be in the middle of a tuple.
1589
+ seen_refs: t.Set[str] = set()
1590
+
1591
+ for nsref in node.find_all(nodes.NSRef):
1592
+ if nsref.name in seen_refs:
1593
+ # Only emit the check for each reference once, in case the same
1594
+ # ref is used multiple times in a tuple, `ns.a, ns.b = c, d`.
1595
+ continue
1596
+
1597
+ seen_refs.add(nsref.name)
1598
+ ref = frame.symbols.ref(nsref.name)
1599
+ self.writeline(f"if not isinstance({ref}, Namespace):")
1600
+ self.indent()
1601
+ self.writeline(
1602
+ "raise TemplateRuntimeError"
1603
+ '("cannot assign attribute on non-namespace object")'
1604
+ )
1605
+ self.outdent()
1606
+
1607
+ self.newline(node)
1608
+ self.visit(node.target, frame)
1609
+ self.write(" = ")
1610
+ self.visit(node.node, frame)
1611
+ self.pop_assign_tracking(frame)
1612
+
1613
+ def visit_AssignBlock(self, node: nodes.AssignBlock, frame: Frame) -> None:
1614
+ self.push_assign_tracking()
1615
+ block_frame = frame.inner()
1616
+ # This is a special case. Since a set block always captures we
1617
+ # will disable output checks. This way one can use set blocks
1618
+ # toplevel even in extended templates.
1619
+ block_frame.require_output_check = False
1620
+ block_frame.symbols.analyze_node(node)
1621
+ self.enter_frame(block_frame)
1622
+ self.buffer(block_frame)
1623
+ self.blockvisit(node.body, block_frame)
1624
+ self.newline(node)
1625
+ self.visit(node.target, frame)
1626
+ self.write(" = (Markup if context.eval_ctx.autoescape else identity)(")
1627
+ if node.filter is not None:
1628
+ self.visit_Filter(node.filter, block_frame)
1629
+ else:
1630
+ self.write(f"concat({block_frame.buffer})")
1631
+ self.write(")")
1632
+ self.pop_assign_tracking(frame)
1633
+ self.leave_frame(block_frame)
1634
+
1635
+ # -- Expression Visitors
1636
+
1637
+ def visit_Name(self, node: nodes.Name, frame: Frame) -> None:
1638
+ if node.ctx == "store" and (
1639
+ frame.toplevel or frame.loop_frame or frame.block_frame
1640
+ ):
1641
+ if self._assign_stack:
1642
+ self._assign_stack[-1].add(node.name)
1643
+ ref = frame.symbols.ref(node.name)
1644
+
1645
+ # If we are looking up a variable we might have to deal with the
1646
+ # case where it's undefined. We can skip that case if the load
1647
+ # instruction indicates a parameter which are always defined.
1648
+ if node.ctx == "load":
1649
+ load = frame.symbols.find_load(ref)
1650
+ if not (
1651
+ load is not None
1652
+ and load[0] == VAR_LOAD_PARAMETER
1653
+ and not self.parameter_is_undeclared(ref)
1654
+ ):
1655
+ self.write(
1656
+ f"(undefined(name={node.name!r}) if {ref} is missing else {ref})"
1657
+ )
1658
+ return
1659
+
1660
+ self.write(ref)
1661
+
1662
+ def visit_NSRef(self, node: nodes.NSRef, frame: Frame) -> None:
1663
+ # NSRef is a dotted assignment target a.b=c, but uses a[b]=c internally.
1664
+ # visit_Assign emits code to validate that each ref is to a Namespace
1665
+ # object only. That can't be emitted here as the ref could be in the
1666
+ # middle of a tuple assignment.
1667
+ ref = frame.symbols.ref(node.name)
1668
+ self.writeline(f"{ref}[{node.attr!r}]")
1669
+
1670
+ def visit_Const(self, node: nodes.Const, frame: Frame) -> None:
1671
+ val = node.as_const(frame.eval_ctx)
1672
+ if isinstance(val, float):
1673
+ self.write(str(val))
1674
+ else:
1675
+ self.write(repr(val))
1676
+
1677
+ def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None:
1678
+ try:
1679
+ self.write(repr(node.as_const(frame.eval_ctx)))
1680
+ except nodes.Impossible:
1681
+ self.write(
1682
+ f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})"
1683
+ )
1684
+
1685
+ def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None:
1686
+ self.write("(")
1687
+ idx = -1
1688
+ for idx, item in enumerate(node.items):
1689
+ if idx:
1690
+ self.write(", ")
1691
+ self.visit(item, frame)
1692
+ self.write(",)" if idx == 0 else ")")
1693
+
1694
+ def visit_List(self, node: nodes.List, frame: Frame) -> None:
1695
+ self.write("[")
1696
+ for idx, item in enumerate(node.items):
1697
+ if idx:
1698
+ self.write(", ")
1699
+ self.visit(item, frame)
1700
+ self.write("]")
1701
+
1702
+ def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None:
1703
+ self.write("{")
1704
+ for idx, item in enumerate(node.items):
1705
+ if idx:
1706
+ self.write(", ")
1707
+ self.visit(item.key, frame)
1708
+ self.write(": ")
1709
+ self.visit(item.value, frame)
1710
+ self.write("}")
1711
+
1712
+ visit_Add = _make_binop("+")
1713
+ visit_Sub = _make_binop("-")
1714
+ visit_Mul = _make_binop("*")
1715
+ visit_Div = _make_binop("/")
1716
+ visit_FloorDiv = _make_binop("//")
1717
+ visit_Pow = _make_binop("**")
1718
+ visit_Mod = _make_binop("%")
1719
+ visit_And = _make_binop("and")
1720
+ visit_Or = _make_binop("or")
1721
+ visit_Pos = _make_unop("+")
1722
+ visit_Neg = _make_unop("-")
1723
+ visit_Not = _make_unop("not ")
1724
+
1725
+ @optimizeconst
1726
+ def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None:
1727
+ if frame.eval_ctx.volatile:
1728
+ func_name = "(markup_join if context.eval_ctx.volatile else str_join)"
1729
+ elif frame.eval_ctx.autoescape:
1730
+ func_name = "markup_join"
1731
+ else:
1732
+ func_name = "str_join"
1733
+ self.write(f"{func_name}((")
1734
+ for arg in node.nodes:
1735
+ self.visit(arg, frame)
1736
+ self.write(", ")
1737
+ self.write("))")
1738
+
1739
+ @optimizeconst
1740
+ def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None:
1741
+ self.write("(")
1742
+ self.visit(node.expr, frame)
1743
+ for op in node.ops:
1744
+ self.visit(op, frame)
1745
+ self.write(")")
1746
+
1747
+ def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None:
1748
+ self.write(f" {operators[node.op]} ")
1749
+ self.visit(node.expr, frame)
1750
+
1751
+ @optimizeconst
1752
+ def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None:
1753
+ if self.environment.is_async:
1754
+ self.write("(await auto_await(")
1755
+
1756
+ self.write("environment.getattr(")
1757
+ self.visit(node.node, frame)
1758
+ self.write(f", {node.attr!r})")
1759
+
1760
+ if self.environment.is_async:
1761
+ self.write("))")
1762
+
1763
+ @optimizeconst
1764
+ def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None:
1765
+ # slices bypass the environment getitem method.
1766
+ if isinstance(node.arg, nodes.Slice):
1767
+ self.visit(node.node, frame)
1768
+ self.write("[")
1769
+ self.visit(node.arg, frame)
1770
+ self.write("]")
1771
+ else:
1772
+ if self.environment.is_async:
1773
+ self.write("(await auto_await(")
1774
+
1775
+ self.write("environment.getitem(")
1776
+ self.visit(node.node, frame)
1777
+ self.write(", ")
1778
+ self.visit(node.arg, frame)
1779
+ self.write(")")
1780
+
1781
+ if self.environment.is_async:
1782
+ self.write("))")
1783
+
1784
+ def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None:
1785
+ if node.start is not None:
1786
+ self.visit(node.start, frame)
1787
+ self.write(":")
1788
+ if node.stop is not None:
1789
+ self.visit(node.stop, frame)
1790
+ if node.step is not None:
1791
+ self.write(":")
1792
+ self.visit(node.step, frame)
1793
+
1794
+ @contextmanager
1795
+ def _filter_test_common(
1796
+ self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool
1797
+ ) -> t.Iterator[None]:
1798
+ if self.environment.is_async:
1799
+ self.write("(await auto_await(")
1800
+
1801
+ if is_filter:
1802
+ self.write(f"{self.filters[node.name]}(")
1803
+ func = self.environment.filters.get(node.name)
1804
+ else:
1805
+ self.write(f"{self.tests[node.name]}(")
1806
+ func = self.environment.tests.get(node.name)
1807
+
1808
+ # When inside an If or CondExpr frame, allow the filter to be
1809
+ # undefined at compile time and only raise an error if it's
1810
+ # actually called at runtime. See pull_dependencies.
1811
+ if func is None and not frame.soft_frame:
1812
+ type_name = "filter" if is_filter else "test"
1813
+ self.fail(f"No {type_name} named {node.name!r}.", node.lineno)
1814
+
1815
+ pass_arg = {
1816
+ _PassArg.context: "context",
1817
+ _PassArg.eval_context: "context.eval_ctx",
1818
+ _PassArg.environment: "environment",
1819
+ }.get(
1820
+ _PassArg.from_obj(func) # type: ignore
1821
+ )
1822
+
1823
+ if pass_arg is not None:
1824
+ self.write(f"{pass_arg}, ")
1825
+
1826
+ # Back to the visitor function to handle visiting the target of
1827
+ # the filter or test.
1828
+ yield
1829
+
1830
+ self.signature(node, frame)
1831
+ self.write(")")
1832
+
1833
+ if self.environment.is_async:
1834
+ self.write("))")
1835
+
1836
+ @optimizeconst
1837
+ def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None:
1838
+ with self._filter_test_common(node, frame, True):
1839
+ # if the filter node is None we are inside a filter block
1840
+ # and want to write to the current buffer
1841
+ if node.node is not None:
1842
+ self.visit(node.node, frame)
1843
+ elif frame.eval_ctx.volatile:
1844
+ self.write(
1845
+ f"(Markup(concat({frame.buffer}))"
1846
+ f" if context.eval_ctx.autoescape else concat({frame.buffer}))"
1847
+ )
1848
+ elif frame.eval_ctx.autoescape:
1849
+ self.write(f"Markup(concat({frame.buffer}))")
1850
+ else:
1851
+ self.write(f"concat({frame.buffer})")
1852
+
1853
+ @optimizeconst
1854
+ def visit_Test(self, node: nodes.Test, frame: Frame) -> None:
1855
+ with self._filter_test_common(node, frame, False):
1856
+ self.visit(node.node, frame)
1857
+
1858
+ @optimizeconst
1859
+ def visit_CondExpr(self, node: nodes.CondExpr, frame: Frame) -> None:
1860
+ frame = frame.soft()
1861
+
1862
+ def write_expr2() -> None:
1863
+ if node.expr2 is not None:
1864
+ self.visit(node.expr2, frame)
1865
+ return
1866
+
1867
+ self.write(
1868
+ f'cond_expr_undefined("the inline if-expression on'
1869
+ f" {self.position(node)} evaluated to false and no else"
1870
+ f' section was defined.")'
1871
+ )
1872
+
1873
+ self.write("(")
1874
+ self.visit(node.expr1, frame)
1875
+ self.write(" if ")
1876
+ self.visit(node.test, frame)
1877
+ self.write(" else ")
1878
+ write_expr2()
1879
+ self.write(")")
1880
+
1881
+ @optimizeconst
1882
+ def visit_Call(
1883
+ self, node: nodes.Call, frame: Frame, forward_caller: bool = False
1884
+ ) -> None:
1885
+ if self.environment.is_async:
1886
+ self.write("(await auto_await(")
1887
+ if self.environment.sandboxed:
1888
+ self.write("environment.call(context, ")
1889
+ else:
1890
+ self.write("context.call(")
1891
+ self.visit(node.node, frame)
1892
+ extra_kwargs = {"caller": "caller"} if forward_caller else None
1893
+ loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {}
1894
+ block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {}
1895
+ if extra_kwargs:
1896
+ extra_kwargs.update(loop_kwargs, **block_kwargs)
1897
+ elif loop_kwargs or block_kwargs:
1898
+ extra_kwargs = dict(loop_kwargs, **block_kwargs)
1899
+ self.signature(node, frame, extra_kwargs)
1900
+ self.write(")")
1901
+ if self.environment.is_async:
1902
+ self.write("))")
1903
+
1904
+ def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None:
1905
+ self.write(node.key + "=")
1906
+ self.visit(node.value, frame)
1907
+
1908
+ # -- Unused nodes for extensions
1909
+
1910
+ def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None:
1911
+ self.write("Markup(")
1912
+ self.visit(node.expr, frame)
1913
+ self.write(")")
1914
+
1915
+ def visit_MarkSafeIfAutoescape(
1916
+ self, node: nodes.MarkSafeIfAutoescape, frame: Frame
1917
+ ) -> None:
1918
+ self.write("(Markup if context.eval_ctx.autoescape else identity)(")
1919
+ self.visit(node.expr, frame)
1920
+ self.write(")")
1921
+
1922
+ def visit_EnvironmentAttribute(
1923
+ self, node: nodes.EnvironmentAttribute, frame: Frame
1924
+ ) -> None:
1925
+ self.write("environment." + node.name)
1926
+
1927
+ def visit_ExtensionAttribute(
1928
+ self, node: nodes.ExtensionAttribute, frame: Frame
1929
+ ) -> None:
1930
+ self.write(f"environment.extensions[{node.identifier!r}].{node.name}")
1931
+
1932
+ def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None:
1933
+ self.write(self.import_aliases[node.importname])
1934
+
1935
+ def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None:
1936
+ self.write(node.name)
1937
+
1938
+ def visit_ContextReference(
1939
+ self, node: nodes.ContextReference, frame: Frame
1940
+ ) -> None:
1941
+ self.write("context")
1942
+
1943
+ def visit_DerivedContextReference(
1944
+ self, node: nodes.DerivedContextReference, frame: Frame
1945
+ ) -> None:
1946
+ self.write(self.derive_context(frame))
1947
+
1948
+ def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None:
1949
+ self.writeline("continue", node)
1950
+
1951
+ def visit_Break(self, node: nodes.Break, frame: Frame) -> None:
1952
+ self.writeline("break", node)
1953
+
1954
+ def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None:
1955
+ scope_frame = frame.inner()
1956
+ scope_frame.symbols.analyze_node(node)
1957
+ self.enter_frame(scope_frame)
1958
+ self.blockvisit(node.body, scope_frame)
1959
+ self.leave_frame(scope_frame)
1960
+
1961
+ def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None:
1962
+ ctx = self.temporary_identifier()
1963
+ self.writeline(f"{ctx} = {self.derive_context(frame)}")
1964
+ self.writeline(f"{ctx}.vars = ")
1965
+ self.visit(node.context, frame)
1966
+ self.push_context_reference(ctx)
1967
+
1968
+ scope_frame = frame.inner(isolated=True)
1969
+ scope_frame.symbols.analyze_node(node)
1970
+ self.enter_frame(scope_frame)
1971
+ self.blockvisit(node.body, scope_frame)
1972
+ self.leave_frame(scope_frame)
1973
+ self.pop_context_reference()
1974
+
1975
+ def visit_EvalContextModifier(
1976
+ self, node: nodes.EvalContextModifier, frame: Frame
1977
+ ) -> None:
1978
+ for keyword in node.options:
1979
+ self.writeline(f"context.eval_ctx.{keyword.key} = ")
1980
+ self.visit(keyword.value, frame)
1981
+ try:
1982
+ val = keyword.value.as_const(frame.eval_ctx)
1983
+ except nodes.Impossible:
1984
+ frame.eval_ctx.volatile = True
1985
+ else:
1986
+ setattr(frame.eval_ctx, keyword.key, val)
1987
+
1988
+ def visit_ScopedEvalContextModifier(
1989
+ self, node: nodes.ScopedEvalContextModifier, frame: Frame
1990
+ ) -> None:
1991
+ old_ctx_name = self.temporary_identifier()
1992
+ saved_ctx = frame.eval_ctx.save()
1993
+ self.writeline(f"{old_ctx_name} = context.eval_ctx.save()")
1994
+ self.visit_EvalContextModifier(node, frame)
1995
+ for child in node.body:
1996
+ self.visit(child, frame)
1997
+ frame.eval_ctx.revert(saved_ctx)
1998
+ self.writeline(f"context.eval_ctx.revert({old_ctx_name})")