Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/__init__.py +57 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/__pycache__/__init__.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/__init__.py +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/__pycache__/__init__.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/__pycache__/directives.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/__pycache__/special_functions.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/directives.py +94 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/special_functions.py +118 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__init__.py +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/anno.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/ast_util.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/cache.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/cfg.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/error_utils.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/errors.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/gast_util.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/inspect_utils.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/loader.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/naming.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/origin_info.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/parser.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/pretty_printer.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/qual_names.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/templates.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/transformer.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/transpiler.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/anno.py +174 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/ast_util.py +344 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/cache.py +93 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/cfg.py +976 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/error_utils.py +230 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/errors.py +27 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/gast_util.py +74 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/inspect_utils.py +321 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/loader.py +102 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/naming.py +53 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/origin_info.py +296 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/parser.py +396 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/pretty_printer.py +130 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/qual_names.py +266 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/templates.py +290 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/transformer.py +538 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/transpiler.py +496 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__init__.py +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/__init__.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/client_lib.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/device_lib.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/pywrap_tf_session.cpython-310.pyc +0 -0
- SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/session.cpython-310.pyc +0 -0
.gitattributes
CHANGED
|
@@ -196,3 +196,4 @@ SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/pl
|
|
| 196 |
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/grappler/_pywrap_tf_optimizer.so filter=lfs diff=lfs merge=lfs -text
|
| 197 |
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/grappler/_pywrap_tf_item.so filter=lfs diff=lfs merge=lfs -text
|
| 198 |
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/profiler/internal/_pywrap_profiler.so filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 196 |
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/grappler/_pywrap_tf_optimizer.so filter=lfs diff=lfs merge=lfs -text
|
| 197 |
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/grappler/_pywrap_tf_item.so filter=lfs diff=lfs merge=lfs -text
|
| 198 |
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/profiler/internal/_pywrap_profiler.so filter=lfs diff=lfs merge=lfs -text
|
| 199 |
+
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/_pywrap_tf_session.so filter=lfs diff=lfs merge=lfs -text
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/__init__.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Conversion of eager-style Python into TensorFlow graph code.
|
| 16 |
+
|
| 17 |
+
NOTE: In TensorFlow 2.0, AutoGraph is automatically applied when using
|
| 18 |
+
`tf.function`. This module contains lower-level APIs for advanced use.
|
| 19 |
+
|
| 20 |
+
AutoGraph transforms a subset of Python which operates on TensorFlow objects
|
| 21 |
+
into equivalent TensorFlow graph code. When executing the graph, it has the same
|
| 22 |
+
effect as if you ran the original code in eager mode.
|
| 23 |
+
Python code which doesn't operate on TensorFlow objects remains functionally
|
| 24 |
+
unchanged, but keep in mind that `tf.function` only executes such code at trace
|
| 25 |
+
time, and generally will not be consistent with eager execution.
|
| 26 |
+
|
| 27 |
+
For more information, see the
|
| 28 |
+
[AutoGraph reference documentation](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/autograph/g3doc/reference/index.md),
|
| 29 |
+
and the [tf.function guide](https://www.tensorflow.org/guide/function#autograph_transformations).
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
from tensorflow.python.util.all_util import remove_undocumented
|
| 33 |
+
|
| 34 |
+
# TODO(mdan): Revisit this list once we finalize the generated code mechanism.
|
| 35 |
+
_allowed_symbols = [
|
| 36 |
+
# Main API
|
| 37 |
+
'AutoGraphError',
|
| 38 |
+
'ConversionOptions',
|
| 39 |
+
'Feature',
|
| 40 |
+
'StackTraceMapper',
|
| 41 |
+
'convert',
|
| 42 |
+
'converted_call',
|
| 43 |
+
'do_not_convert',
|
| 44 |
+
'to_code',
|
| 45 |
+
'to_graph',
|
| 46 |
+
# Overloaded operators
|
| 47 |
+
'operators',
|
| 48 |
+
# Python language "extensions"
|
| 49 |
+
'set_element_type',
|
| 50 |
+
'set_loop_options',
|
| 51 |
+
'stack',
|
| 52 |
+
'tensor_list',
|
| 53 |
+
# Utilities: to be removed
|
| 54 |
+
'utils',
|
| 55 |
+
]
|
| 56 |
+
|
| 57 |
+
remove_undocumented(__name__, _allowed_symbols)
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (1.46 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/__init__.py
ADDED
|
File without changes
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (208 Bytes). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/__pycache__/directives.cpython-310.pyc
ADDED
|
Binary file (2.76 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/__pycache__/special_functions.cpython-310.pyc
ADDED
|
Binary file (3.87 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/directives.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Directives are special no-op functions that serve as compilation markers.
|
| 16 |
+
|
| 17 |
+
They provide static information like type hints, compilation and TensorFlow
|
| 18 |
+
overrides.
|
| 19 |
+
|
| 20 |
+
These serve as annotations in the compiled code, allowing the user some control
|
| 21 |
+
over the compilation process. They have no functional role at runtime.
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
from tensorflow.python.util.tf_export import tf_export
|
| 25 |
+
|
| 26 |
+
UNSPECIFIED = object()
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def set_element_type(entity, dtype, shape=UNSPECIFIED):
|
| 30 |
+
"""Indicates that the entity is expected hold items of specified type/shape.
|
| 31 |
+
|
| 32 |
+
The staged TensorFlow ops will reflect and assert this data type. Ignored
|
| 33 |
+
otherwise.
|
| 34 |
+
|
| 35 |
+
Args:
|
| 36 |
+
entity: The entity to annotate.
|
| 37 |
+
dtype: TensorFlow dtype value to assert for entity.
|
| 38 |
+
shape: Optional shape to assert for entity.
|
| 39 |
+
"""
|
| 40 |
+
del entity
|
| 41 |
+
del dtype
|
| 42 |
+
del shape
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
@tf_export('autograph.experimental.set_loop_options')
|
| 46 |
+
def set_loop_options(
|
| 47 |
+
parallel_iterations=UNSPECIFIED,
|
| 48 |
+
swap_memory=UNSPECIFIED,
|
| 49 |
+
maximum_iterations=UNSPECIFIED,
|
| 50 |
+
shape_invariants=UNSPECIFIED):
|
| 51 |
+
"""Specifies additional arguments to be passed to the enclosing while_loop.
|
| 52 |
+
|
| 53 |
+
The parameters apply to and only to the immediately enclosing loop. It only
|
| 54 |
+
has effect if the loop is staged as a TF while_loop; otherwise the parameters
|
| 55 |
+
have no effect.
|
| 56 |
+
|
| 57 |
+
Usage:
|
| 58 |
+
|
| 59 |
+
>>> @tf.function(autograph=True)
|
| 60 |
+
... def f():
|
| 61 |
+
... n = 0
|
| 62 |
+
... for i in tf.range(10):
|
| 63 |
+
... tf.autograph.experimental.set_loop_options(maximum_iterations=3)
|
| 64 |
+
... n += 1
|
| 65 |
+
... return n
|
| 66 |
+
|
| 67 |
+
>>> @tf.function(autograph=True)
|
| 68 |
+
... def f():
|
| 69 |
+
... v = tf.constant((0,))
|
| 70 |
+
... for i in tf.range(3):
|
| 71 |
+
... tf.autograph.experimental.set_loop_options(
|
| 72 |
+
... shape_invariants=[(v, tf.TensorShape([None]))]
|
| 73 |
+
... )
|
| 74 |
+
... v = tf.concat((v, [i]), 0)
|
| 75 |
+
... return v
|
| 76 |
+
|
| 77 |
+
Also see tf.while_loop.
|
| 78 |
+
|
| 79 |
+
Args:
|
| 80 |
+
parallel_iterations: The maximum number of iterations allowed to run in
|
| 81 |
+
parallel at any given time. Note that this does not guarantee parallel
|
| 82 |
+
execution.
|
| 83 |
+
swap_memory: Whether to store intermediate values needed for
|
| 84 |
+
gradients on the CPU instead of GPU.
|
| 85 |
+
maximum_iterations: Allows limiting the total number of iterations executed
|
| 86 |
+
by the loop.
|
| 87 |
+
shape_invariants: Allows controlling the argument with the same name passed
|
| 88 |
+
to tf.while_loop. Unlike tf.while_loop, this is a list of
|
| 89 |
+
`(tensor, shape)` pairs.
|
| 90 |
+
"""
|
| 91 |
+
del parallel_iterations
|
| 92 |
+
del swap_memory
|
| 93 |
+
del maximum_iterations
|
| 94 |
+
del shape_invariants
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/lang/special_functions.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Special functions that only make sense for AutoGraph.
|
| 16 |
+
|
| 17 |
+
These functions are meant to ensure feature parity between Python and AutoGraph,
|
| 18 |
+
so that the exact same code works in both modes. In general, AutoGraph will
|
| 19 |
+
replace these calls.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
from tensorflow.python.autograph.operators import data_structures
|
| 23 |
+
from tensorflow.python.framework import constant_op
|
| 24 |
+
from tensorflow.python.framework import tensor_util
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def _validate_list_constructor(elements, element_dtype, element_shape):
|
| 28 |
+
"""Validates the inputs of tensor_list."""
|
| 29 |
+
if element_dtype is not None and element_shape is not None:
|
| 30 |
+
return
|
| 31 |
+
if tensor_util.is_tf_type(elements):
|
| 32 |
+
return
|
| 33 |
+
if isinstance(elements, (list, tuple)):
|
| 34 |
+
if elements:
|
| 35 |
+
return
|
| 36 |
+
else:
|
| 37 |
+
raise ValueError(
|
| 38 |
+
'element_dtype and element_shape are required when elements are'
|
| 39 |
+
' empty')
|
| 40 |
+
|
| 41 |
+
raise ValueError(
|
| 42 |
+
'unknown type for elements: {}; only Tensor, list and tuple are'
|
| 43 |
+
' allowed'.format(type(elements)))
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def match_staging_level(value, like_value):
|
| 47 |
+
"""Casts a value to be staged at the same level as another."""
|
| 48 |
+
if tensor_util.is_tf_type(like_value):
|
| 49 |
+
return constant_op.constant(value)
|
| 50 |
+
return value
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def tensor_list(elements,
|
| 54 |
+
element_dtype=None,
|
| 55 |
+
element_shape=None,
|
| 56 |
+
use_tensor_array=False):
|
| 57 |
+
"""Creates an tensor list and populates it with the given elements.
|
| 58 |
+
|
| 59 |
+
This function provides a more uniform access to tensor lists and tensor
|
| 60 |
+
arrays, and allows optional initialization.
|
| 61 |
+
|
| 62 |
+
Note: this function is a simplified wrapper. If you need greater control,
|
| 63 |
+
it is recommended to use the underlying implementation directly.
|
| 64 |
+
|
| 65 |
+
Args:
|
| 66 |
+
elements: Iterable[tf.Tensor, ...], the elements to initially fill the list
|
| 67 |
+
with
|
| 68 |
+
element_dtype: Optional[tf.DType], data type for the elements in the list;
|
| 69 |
+
required if the list is empty
|
| 70 |
+
element_shape: Optional[tf.TensorShape], shape for the elements in the list;
|
| 71 |
+
required if the list is empty
|
| 72 |
+
use_tensor_array: bool, whether to use the more compatible but restrictive
|
| 73 |
+
tf.TensorArray implementation
|
| 74 |
+
Returns:
|
| 75 |
+
Union[tf.Tensor, tf.TensorArray], the new list.
|
| 76 |
+
Raises:
|
| 77 |
+
ValueError: for invalid arguments
|
| 78 |
+
"""
|
| 79 |
+
_validate_list_constructor(elements, element_dtype, element_shape)
|
| 80 |
+
if use_tensor_array:
|
| 81 |
+
return data_structures.tf_tensor_array_new(elements, element_dtype,
|
| 82 |
+
element_shape)
|
| 83 |
+
else:
|
| 84 |
+
return data_structures.tf_tensor_list_new(elements, element_dtype,
|
| 85 |
+
element_shape)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def stack(list_or_tensor, element_dtype=None, strict=True):
|
| 89 |
+
"""Stacks the input, if it admits the notion of stacking.
|
| 90 |
+
|
| 91 |
+
For example, a list of tensors can be stacked into a larger tensor. This
|
| 92 |
+
function is similar to tf.stack, but it accepts non-lists and lists of
|
| 93 |
+
non-tensors as arguments. In the latter case, the function does nothing.
|
| 94 |
+
|
| 95 |
+
Args:
|
| 96 |
+
list_or_tensor: Any
|
| 97 |
+
element_dtype: tf.DType, optional dtypedtype for the elements in the list.
|
| 98 |
+
Required if the input is stackable, and the list is untyped.
|
| 99 |
+
strict: bool, if True an error is raised if the input is not stackable.
|
| 100 |
+
Otherwise the function is a no-op.
|
| 101 |
+
|
| 102 |
+
Returns:
|
| 103 |
+
Any, if the input is stackable, the result will be a tf.Tensor. Otherwise,
|
| 104 |
+
if strict=False, the result will be list_or_tensor.
|
| 105 |
+
|
| 106 |
+
Raises:
|
| 107 |
+
ValueError: if strict=True and the input is not stackable.
|
| 108 |
+
"""
|
| 109 |
+
if strict:
|
| 110 |
+
def raise_error(x):
|
| 111 |
+
raise ValueError('%s must be stackable when strict=True' % x)
|
| 112 |
+
original_call = raise_error
|
| 113 |
+
else:
|
| 114 |
+
original_call = lambda x: x
|
| 115 |
+
return data_structures.list_stack(
|
| 116 |
+
list_or_tensor,
|
| 117 |
+
data_structures.ListStackOpts(
|
| 118 |
+
element_dtype=element_dtype, original_call=original_call))
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__init__.py
ADDED
|
File without changes
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/anno.cpython-310.pyc
ADDED
|
Binary file (5.54 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/ast_util.cpython-310.pyc
ADDED
|
Binary file (9.73 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/cache.cpython-310.pyc
ADDED
|
Binary file (2.96 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/cfg.cpython-310.pyc
ADDED
|
Binary file (27.7 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/error_utils.cpython-310.pyc
ADDED
|
Binary file (5.95 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/errors.cpython-310.pyc
ADDED
|
Binary file (868 Bytes). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/gast_util.cpython-310.pyc
ADDED
|
Binary file (1.45 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/inspect_utils.cpython-310.pyc
ADDED
|
Binary file (8.38 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/loader.cpython-310.pyc
ADDED
|
Binary file (2.64 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/naming.cpython-310.pyc
ADDED
|
Binary file (1.34 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/origin_info.cpython-310.pyc
ADDED
|
Binary file (8.09 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/parser.cpython-310.pyc
ADDED
|
Binary file (9.68 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/pretty_printer.cpython-310.pyc
ADDED
|
Binary file (3.36 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/qual_names.cpython-310.pyc
ADDED
|
Binary file (8.09 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/templates.cpython-310.pyc
ADDED
|
Binary file (8.98 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/transformer.cpython-310.pyc
ADDED
|
Binary file (15.9 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/__pycache__/transpiler.cpython-310.pyc
ADDED
|
Binary file (16 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/anno.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""AST node annotation support.
|
| 16 |
+
|
| 17 |
+
Adapted from Tangent.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
import enum
|
| 21 |
+
|
| 22 |
+
# pylint:disable=g-bad-import-order
|
| 23 |
+
|
| 24 |
+
import gast
|
| 25 |
+
# pylint:enable=g-bad-import-order
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
# TODO(mdan): Shorten the names.
|
| 29 |
+
# These names are heavily used, and anno.blaa
|
| 30 |
+
# TODO(mdan): Replace the attr-dict mechanism with a more typed solution.
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
class NoValue(enum.Enum):
|
| 34 |
+
"""Base class for different types of AST annotations."""
|
| 35 |
+
|
| 36 |
+
def of(self, node, default=None):
|
| 37 |
+
return getanno(node, self, default=default)
|
| 38 |
+
|
| 39 |
+
def add_to(self, node, value):
|
| 40 |
+
setanno(node, self, value)
|
| 41 |
+
|
| 42 |
+
def exists(self, node):
|
| 43 |
+
return hasanno(node, self)
|
| 44 |
+
|
| 45 |
+
def __repr__(self):
|
| 46 |
+
return str(self.name)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class Basic(NoValue):
|
| 50 |
+
"""Container for basic annotation keys.
|
| 51 |
+
|
| 52 |
+
The enum values are used strictly for documentation purposes.
|
| 53 |
+
"""
|
| 54 |
+
|
| 55 |
+
QN = 'Qualified name, as it appeared in the code. See qual_names.py.'
|
| 56 |
+
SKIP_PROCESSING = (
|
| 57 |
+
'This node should be preserved as is and not processed any further.')
|
| 58 |
+
INDENT_BLOCK_REMAINDER = (
|
| 59 |
+
'When a node is annotated with this, the remainder of the block should'
|
| 60 |
+
' be indented below it. The annotation contains a tuple'
|
| 61 |
+
' (new_body, name_map), where `new_body` is the new indented block and'
|
| 62 |
+
' `name_map` allows renaming symbols.')
|
| 63 |
+
ORIGIN = ('Information about the source code that converted code originated'
|
| 64 |
+
' from. See origin_information.py.')
|
| 65 |
+
DIRECTIVES = ('User directives associated with a statement or a variable.'
|
| 66 |
+
' Typically, they affect the immediately-enclosing statement.')
|
| 67 |
+
|
| 68 |
+
EXTRA_LOOP_TEST = (
|
| 69 |
+
'A special annotation containing additional test code to be executed in'
|
| 70 |
+
' for loops.')
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
class Static(NoValue):
|
| 74 |
+
"""Container for static analysis annotation keys.
|
| 75 |
+
|
| 76 |
+
The enum values are used strictly for documentation purposes.
|
| 77 |
+
"""
|
| 78 |
+
|
| 79 |
+
# Symbols
|
| 80 |
+
# These flags are boolean.
|
| 81 |
+
IS_PARAM = 'Symbol is a parameter to the function being analyzed.'
|
| 82 |
+
|
| 83 |
+
# Scopes
|
| 84 |
+
# Scopes are represented by objects of type activity.Scope.
|
| 85 |
+
SCOPE = 'The scope for the annotated node. See activity.py.'
|
| 86 |
+
# TODO(mdan): Drop these in favor of accessing the child's SCOPE.
|
| 87 |
+
ARGS_SCOPE = 'The scope for the argument list of a function call.'
|
| 88 |
+
COND_SCOPE = 'The scope for the test node of a conditional statement.'
|
| 89 |
+
BODY_SCOPE = (
|
| 90 |
+
'The scope for the main body of a statement (True branch for if '
|
| 91 |
+
'statements, main body for loops).')
|
| 92 |
+
ORELSE_SCOPE = (
|
| 93 |
+
'The scope for the orelse body of a statement (False branch for if '
|
| 94 |
+
'statements, orelse body for loops).')
|
| 95 |
+
|
| 96 |
+
# Static analysis annotations.
|
| 97 |
+
DEFINITIONS = (
|
| 98 |
+
'Reaching definition information. See reaching_definitions.py.')
|
| 99 |
+
ORIG_DEFINITIONS = (
|
| 100 |
+
'The value of DEFINITIONS that applied to the original code before any'
|
| 101 |
+
' conversion.')
|
| 102 |
+
DEFINED_FNS_IN = (
|
| 103 |
+
'Local function definitions that may exist when exiting the node. See'
|
| 104 |
+
' reaching_fndefs.py')
|
| 105 |
+
DEFINED_VARS_IN = (
|
| 106 |
+
'Symbols defined when entering the node. See reaching_definitions.py.')
|
| 107 |
+
LIVE_VARS_OUT = ('Symbols live when exiting the node. See liveness.py.')
|
| 108 |
+
LIVE_VARS_IN = ('Symbols live when entering the node. See liveness.py.')
|
| 109 |
+
TYPES = 'Static type information. See type_inference.py.'
|
| 110 |
+
CLOSURE_TYPES = 'Types of closure symbols at each detected call site.'
|
| 111 |
+
VALUE = 'Static value information. See type_inference.py.'
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
FAIL = object()
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def keys(node, field_name='___pyct_anno'):
|
| 118 |
+
if not hasattr(node, field_name):
|
| 119 |
+
return frozenset()
|
| 120 |
+
return frozenset(getattr(node, field_name).keys())
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def getanno(node, key, default=FAIL, field_name='___pyct_anno'):
|
| 124 |
+
if (default is FAIL or (hasattr(node, field_name) and
|
| 125 |
+
(key in getattr(node, field_name)))):
|
| 126 |
+
return getattr(node, field_name)[key]
|
| 127 |
+
return default
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def hasanno(node, key, field_name='___pyct_anno'):
|
| 131 |
+
return hasattr(node, field_name) and key in getattr(node, field_name)
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def setanno(node, key, value, field_name='___pyct_anno'):
|
| 135 |
+
annotations = getattr(node, field_name, {})
|
| 136 |
+
setattr(node, field_name, annotations)
|
| 137 |
+
annotations[key] = value
|
| 138 |
+
|
| 139 |
+
# So that the annotations survive gast_to_ast() and ast_to_gast()
|
| 140 |
+
if field_name not in node._fields:
|
| 141 |
+
node._fields += (field_name,)
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def delanno(node, key, field_name='___pyct_anno'):
|
| 145 |
+
annotations = getattr(node, field_name)
|
| 146 |
+
del annotations[key]
|
| 147 |
+
if not annotations:
|
| 148 |
+
delattr(node, field_name)
|
| 149 |
+
node._fields = tuple(f for f in node._fields if f != field_name)
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def copyanno(from_node, to_node, key, field_name='___pyct_anno'):
|
| 153 |
+
if hasanno(from_node, key, field_name=field_name):
|
| 154 |
+
setanno(
|
| 155 |
+
to_node,
|
| 156 |
+
key,
|
| 157 |
+
getanno(from_node, key, field_name=field_name),
|
| 158 |
+
field_name=field_name)
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
def dup(node, copy_map, field_name='___pyct_anno'):
|
| 162 |
+
"""Recursively copies annotations in an AST tree.
|
| 163 |
+
|
| 164 |
+
Args:
|
| 165 |
+
node: ast.AST
|
| 166 |
+
copy_map: Dict[Hashable, Hashable], maps a source anno key to a destination
|
| 167 |
+
key. All annotations with the source key will be copied to identical
|
| 168 |
+
annotations with the destination key.
|
| 169 |
+
field_name: str
|
| 170 |
+
"""
|
| 171 |
+
for n in gast.walk(node):
|
| 172 |
+
for k in copy_map:
|
| 173 |
+
if hasanno(n, k, field_name):
|
| 174 |
+
setanno(n, copy_map[k], getanno(n, k, field_name), field_name)
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/ast_util.py
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""AST manipulation utilities."""
|
| 16 |
+
|
| 17 |
+
import ast
|
| 18 |
+
|
| 19 |
+
import gast
|
| 20 |
+
|
| 21 |
+
from tensorflow.python.autograph.pyct import anno
|
| 22 |
+
from tensorflow.python.autograph.pyct import parser
|
| 23 |
+
from tensorflow.python.autograph.pyct import qual_names
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class CleanCopier(object):
|
| 27 |
+
"""NodeTransformer-like visitor that copies an AST."""
|
| 28 |
+
|
| 29 |
+
def __init__(self, preserve_annos):
|
| 30 |
+
super(CleanCopier, self).__init__()
|
| 31 |
+
self.preserve_annos = preserve_annos
|
| 32 |
+
|
| 33 |
+
def copy(self, node):
|
| 34 |
+
"""Returns a deep copy of node (excluding some fields, see copy_clean)."""
|
| 35 |
+
|
| 36 |
+
if isinstance(node, list):
|
| 37 |
+
return [self.copy(n) for n in node]
|
| 38 |
+
elif isinstance(node, tuple):
|
| 39 |
+
return tuple(self.copy(n) for n in node)
|
| 40 |
+
elif not isinstance(node, (gast.AST, ast.AST)):
|
| 41 |
+
# Assuming everything that's not an AST, list or tuple is a value type
|
| 42 |
+
# and may simply be assigned.
|
| 43 |
+
return node
|
| 44 |
+
|
| 45 |
+
assert isinstance(node, (gast.AST, ast.AST))
|
| 46 |
+
|
| 47 |
+
new_fields = {}
|
| 48 |
+
for f in node._fields:
|
| 49 |
+
if not f.startswith('__') and hasattr(node, f):
|
| 50 |
+
new_fields[f] = self.copy(getattr(node, f))
|
| 51 |
+
new_node = type(node)(**new_fields)
|
| 52 |
+
|
| 53 |
+
if self.preserve_annos:
|
| 54 |
+
for k in self.preserve_annos:
|
| 55 |
+
anno.copyanno(node, new_node, k)
|
| 56 |
+
return new_node
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def copy_clean(node, preserve_annos=None):
|
| 60 |
+
"""Creates a deep copy of an AST.
|
| 61 |
+
|
| 62 |
+
The copy will not include fields that are prefixed by '__', with the
|
| 63 |
+
exception of user-specified annotations.
|
| 64 |
+
|
| 65 |
+
Args:
|
| 66 |
+
node: ast.AST
|
| 67 |
+
preserve_annos: Optional[Set[Hashable]], annotation keys to include in the
|
| 68 |
+
copy
|
| 69 |
+
Returns:
|
| 70 |
+
ast.AST
|
| 71 |
+
"""
|
| 72 |
+
return CleanCopier(preserve_annos).copy(node)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class SymbolRenamer(gast.NodeTransformer):
|
| 76 |
+
"""Transformer that can rename symbols to a simple names."""
|
| 77 |
+
|
| 78 |
+
def __init__(self, name_map):
|
| 79 |
+
self.name_map = name_map
|
| 80 |
+
|
| 81 |
+
def _process_name_node(self, node):
|
| 82 |
+
qn = anno.getanno(node, anno.Basic.QN)
|
| 83 |
+
if qn in self.name_map:
|
| 84 |
+
new_node = gast.Name(
|
| 85 |
+
str(self.name_map[qn]),
|
| 86 |
+
ctx=node.ctx,
|
| 87 |
+
annotation=None,
|
| 88 |
+
type_comment=None)
|
| 89 |
+
# All annotations get carried over.
|
| 90 |
+
for k in anno.keys(node):
|
| 91 |
+
anno.copyanno(node, new_node, k)
|
| 92 |
+
return new_node
|
| 93 |
+
return self.generic_visit(node)
|
| 94 |
+
|
| 95 |
+
def _process_list_of_strings(self, names):
|
| 96 |
+
for i in range(len(names)):
|
| 97 |
+
qn = qual_names.QN(names[i])
|
| 98 |
+
if qn in self.name_map:
|
| 99 |
+
names[i] = str(self.name_map[qn])
|
| 100 |
+
return names
|
| 101 |
+
|
| 102 |
+
def visit_Nonlocal(self, node):
|
| 103 |
+
node.names = self._process_list_of_strings(node.names)
|
| 104 |
+
return node
|
| 105 |
+
|
| 106 |
+
def visit_Global(self, node):
|
| 107 |
+
node.names = self._process_list_of_strings(node.names)
|
| 108 |
+
return node
|
| 109 |
+
|
| 110 |
+
def visit_Name(self, node):
|
| 111 |
+
return self._process_name_node(node)
|
| 112 |
+
|
| 113 |
+
def visit_Attribute(self, node):
|
| 114 |
+
if anno.hasanno(node, anno.Basic.QN):
|
| 115 |
+
return self._process_name_node(node)
|
| 116 |
+
# Renaming attributes is not supported.
|
| 117 |
+
return self.generic_visit(node)
|
| 118 |
+
|
| 119 |
+
def visit_FunctionDef(self, node):
|
| 120 |
+
qn = qual_names.QN(node.name)
|
| 121 |
+
if qn in self.name_map:
|
| 122 |
+
node.name = str(self.name_map[qn])
|
| 123 |
+
return self.generic_visit(node)
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def rename_symbols(node, name_map):
|
| 127 |
+
"""Renames symbols in an AST. Requires qual_names annotations."""
|
| 128 |
+
renamer = SymbolRenamer(name_map)
|
| 129 |
+
if isinstance(node, list):
|
| 130 |
+
return [renamer.visit(n) for n in node]
|
| 131 |
+
elif isinstance(node, tuple):
|
| 132 |
+
return tuple(renamer.visit(n) for n in node)
|
| 133 |
+
return renamer.visit(node)
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def keywords_to_dict(keywords):
|
| 137 |
+
"""Converts a list of ast.keyword objects to a dict."""
|
| 138 |
+
keys = []
|
| 139 |
+
values = []
|
| 140 |
+
for kw in keywords:
|
| 141 |
+
keys.append(gast.Constant(kw.arg, kind=None))
|
| 142 |
+
values.append(kw.value)
|
| 143 |
+
return gast.Dict(keys=keys, values=values)
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
class PatternMatcher(gast.NodeVisitor):
|
| 147 |
+
"""Matches a node against a pattern represented by a node."""
|
| 148 |
+
|
| 149 |
+
def __init__(self, pattern):
|
| 150 |
+
self.pattern = pattern
|
| 151 |
+
self.pattern_stack = []
|
| 152 |
+
self.matches = True
|
| 153 |
+
|
| 154 |
+
def compare_and_visit(self, node, pattern):
|
| 155 |
+
self.pattern_stack.append(self.pattern)
|
| 156 |
+
self.pattern = pattern
|
| 157 |
+
self.generic_visit(node)
|
| 158 |
+
self.pattern = self.pattern_stack.pop()
|
| 159 |
+
|
| 160 |
+
def no_match(self):
|
| 161 |
+
self.matches = False
|
| 162 |
+
return False
|
| 163 |
+
|
| 164 |
+
def is_wildcard(self, p):
|
| 165 |
+
if isinstance(p, (list, tuple)) and len(p) == 1:
|
| 166 |
+
p, = p
|
| 167 |
+
if isinstance(p, gast.Name) and p.id == '_':
|
| 168 |
+
return True
|
| 169 |
+
if p == '_':
|
| 170 |
+
return True
|
| 171 |
+
return False
|
| 172 |
+
|
| 173 |
+
def generic_visit(self, node):
|
| 174 |
+
if not self.matches:
|
| 175 |
+
return
|
| 176 |
+
|
| 177 |
+
pattern = self.pattern
|
| 178 |
+
for f in node._fields:
|
| 179 |
+
if f.startswith('__'):
|
| 180 |
+
continue
|
| 181 |
+
|
| 182 |
+
if not hasattr(node, f):
|
| 183 |
+
if hasattr(pattern, f) and getattr(pattern, f):
|
| 184 |
+
return self.no_match()
|
| 185 |
+
else:
|
| 186 |
+
continue
|
| 187 |
+
if not hasattr(pattern, f):
|
| 188 |
+
return self.no_match()
|
| 189 |
+
|
| 190 |
+
v = getattr(node, f)
|
| 191 |
+
p = getattr(pattern, f)
|
| 192 |
+
|
| 193 |
+
if self.is_wildcard(p):
|
| 194 |
+
continue
|
| 195 |
+
if isinstance(v, (list, tuple)):
|
| 196 |
+
if not isinstance(p, (list, tuple)) or len(v) != len(p):
|
| 197 |
+
return self.no_match()
|
| 198 |
+
for v_item, p_item in zip(v, p):
|
| 199 |
+
self.compare_and_visit(v_item, p_item)
|
| 200 |
+
elif isinstance(v, (gast.AST, ast.AST)):
|
| 201 |
+
if not isinstance(v, type(p)) and not isinstance(p, type(v)):
|
| 202 |
+
return self.no_match()
|
| 203 |
+
self.compare_and_visit(v, p)
|
| 204 |
+
else:
|
| 205 |
+
# Assume everything else is a value type.
|
| 206 |
+
if v != p:
|
| 207 |
+
return self.no_match()
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def matches(node, pattern):
|
| 211 |
+
"""Basic pattern matcher for AST.
|
| 212 |
+
|
| 213 |
+
The pattern may contain wildcards represented by the symbol '_'. A node
|
| 214 |
+
matches a pattern if for every node in the tree, either there is a node of
|
| 215 |
+
the same type in pattern, or a Name node with id='_'.
|
| 216 |
+
|
| 217 |
+
Args:
|
| 218 |
+
node: ast.AST
|
| 219 |
+
pattern: ast.AST
|
| 220 |
+
Returns:
|
| 221 |
+
bool
|
| 222 |
+
"""
|
| 223 |
+
if isinstance(pattern, str):
|
| 224 |
+
pattern = parser.parse_str(pattern)
|
| 225 |
+
|
| 226 |
+
matcher = PatternMatcher(pattern)
|
| 227 |
+
matcher.visit(node)
|
| 228 |
+
return matcher.matches
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
# TODO(mdan): Once we have error tracing, we may be able to just go to SSA.
|
| 232 |
+
def apply_to_single_assignments(targets, values, apply_fn):
|
| 233 |
+
"""Applies a function to each individual assignment.
|
| 234 |
+
|
| 235 |
+
This function can process a possibly-unpacked (e.g. a, b = c, d) assignment.
|
| 236 |
+
It tries to break down the unpacking if possible. In effect, it has the same
|
| 237 |
+
effect as passing the assigned values in SSA form to apply_fn.
|
| 238 |
+
|
| 239 |
+
Examples:
|
| 240 |
+
|
| 241 |
+
The following will result in apply_fn(a, c), apply_fn(b, d):
|
| 242 |
+
|
| 243 |
+
a, b = c, d
|
| 244 |
+
|
| 245 |
+
The following will result in apply_fn(a, c[0]), apply_fn(b, c[1]):
|
| 246 |
+
|
| 247 |
+
a, b = c
|
| 248 |
+
|
| 249 |
+
The following will result in apply_fn(a, (b, c)):
|
| 250 |
+
|
| 251 |
+
a = b, c
|
| 252 |
+
|
| 253 |
+
It uses the visitor pattern to allow subclasses to process single
|
| 254 |
+
assignments individually.
|
| 255 |
+
|
| 256 |
+
Args:
|
| 257 |
+
targets: Union[List[ast.AST, ...], Tuple[ast.AST, ...], ast.AST, should be
|
| 258 |
+
used with the targets field of an ast.Assign node
|
| 259 |
+
values: ast.AST
|
| 260 |
+
apply_fn: Callable[[ast.AST, ast.AST], None], called with the
|
| 261 |
+
respective nodes of each single assignment
|
| 262 |
+
"""
|
| 263 |
+
if not isinstance(targets, (list, tuple)):
|
| 264 |
+
targets = (targets,)
|
| 265 |
+
for target in targets:
|
| 266 |
+
if isinstance(target, (gast.Tuple, gast.List)):
|
| 267 |
+
for i in range(len(target.elts)):
|
| 268 |
+
target_el = target.elts[i]
|
| 269 |
+
if isinstance(values, (gast.Tuple, gast.List)):
|
| 270 |
+
value_el = values.elts[i]
|
| 271 |
+
else:
|
| 272 |
+
idx = parser.parse_expression(str(i))
|
| 273 |
+
value_el = gast.Subscript(values, idx, ctx=gast.Load())
|
| 274 |
+
apply_to_single_assignments(target_el, value_el, apply_fn)
|
| 275 |
+
else:
|
| 276 |
+
apply_fn(target, values)
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
def parallel_walk(node, other):
|
| 280 |
+
"""Walks two ASTs in parallel.
|
| 281 |
+
|
| 282 |
+
The two trees must have identical structure.
|
| 283 |
+
|
| 284 |
+
Args:
|
| 285 |
+
node: Union[ast.AST, Iterable[ast.AST]]
|
| 286 |
+
other: Union[ast.AST, Iterable[ast.AST]]
|
| 287 |
+
Yields:
|
| 288 |
+
Tuple[ast.AST, ast.AST]
|
| 289 |
+
Raises:
|
| 290 |
+
ValueError: if the two trees don't have identical structure.
|
| 291 |
+
"""
|
| 292 |
+
if isinstance(node, (list, tuple)):
|
| 293 |
+
node_stack = list(node)
|
| 294 |
+
else:
|
| 295 |
+
node_stack = [node]
|
| 296 |
+
|
| 297 |
+
if isinstance(other, (list, tuple)):
|
| 298 |
+
other_stack = list(other)
|
| 299 |
+
else:
|
| 300 |
+
other_stack = [other]
|
| 301 |
+
|
| 302 |
+
while node_stack and other_stack:
|
| 303 |
+
assert len(node_stack) == len(other_stack)
|
| 304 |
+
n = node_stack.pop()
|
| 305 |
+
o = other_stack.pop()
|
| 306 |
+
|
| 307 |
+
if ((not isinstance(n, (ast.AST, gast.AST, str)) and n is not None) or
|
| 308 |
+
(not isinstance(o, (ast.AST, gast.AST, str)) and n is not None) or
|
| 309 |
+
n.__class__.__name__ != o.__class__.__name__):
|
| 310 |
+
raise ValueError('inconsistent nodes: {} ({}) and {} ({})'.format(
|
| 311 |
+
n, n.__class__.__name__, o, o.__class__.__name__))
|
| 312 |
+
|
| 313 |
+
yield n, o
|
| 314 |
+
|
| 315 |
+
if isinstance(n, str):
|
| 316 |
+
assert isinstance(o, str), 'The check above should have ensured this'
|
| 317 |
+
continue
|
| 318 |
+
if n is None:
|
| 319 |
+
assert o is None, 'The check above should have ensured this'
|
| 320 |
+
continue
|
| 321 |
+
|
| 322 |
+
for f in n._fields:
|
| 323 |
+
n_child = getattr(n, f, None)
|
| 324 |
+
o_child = getattr(o, f, None)
|
| 325 |
+
if f.startswith('__') or n_child is None or o_child is None:
|
| 326 |
+
continue
|
| 327 |
+
|
| 328 |
+
if isinstance(n_child, (list, tuple)):
|
| 329 |
+
if (not isinstance(o_child, (list, tuple)) or
|
| 330 |
+
len(n_child) != len(o_child)):
|
| 331 |
+
raise ValueError(
|
| 332 |
+
'inconsistent values for field {}: {} and {}'.format(
|
| 333 |
+
f, n_child, o_child))
|
| 334 |
+
node_stack.extend(n_child)
|
| 335 |
+
other_stack.extend(o_child)
|
| 336 |
+
|
| 337 |
+
elif isinstance(n_child, (gast.AST, ast.AST)):
|
| 338 |
+
node_stack.append(n_child)
|
| 339 |
+
other_stack.append(o_child)
|
| 340 |
+
|
| 341 |
+
elif n_child != o_child:
|
| 342 |
+
raise ValueError(
|
| 343 |
+
'inconsistent values for field {}: {} and {}'.format(
|
| 344 |
+
f, n_child, o_child))
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/cache.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Caching utilities."""
|
| 16 |
+
|
| 17 |
+
import inspect
|
| 18 |
+
import weakref
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
# TODO(mdan): Add a garbage collection hook for cleaning up modules.
|
| 22 |
+
class _TransformedFnCache(object):
|
| 23 |
+
"""Generic hierarchical cache for transformed functions.
|
| 24 |
+
|
| 25 |
+
The keys are soft references (i.e. they are discarded when the key is
|
| 26 |
+
destroyed) created from the source function by `_get_key`. The subkeys are
|
| 27 |
+
strong references and can be any value. Typically they identify different
|
| 28 |
+
kinds of transformation.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
__slots__ = ('_cache',)
|
| 32 |
+
|
| 33 |
+
def __init__(self):
|
| 34 |
+
self._cache = weakref.WeakKeyDictionary()
|
| 35 |
+
|
| 36 |
+
def _get_key(self, entity):
|
| 37 |
+
raise NotImplementedError('subclasses must override')
|
| 38 |
+
|
| 39 |
+
def has(self, entity, subkey):
|
| 40 |
+
key = self._get_key(entity)
|
| 41 |
+
parent = self._cache.get(key, None)
|
| 42 |
+
if parent is None:
|
| 43 |
+
return False
|
| 44 |
+
return subkey in parent
|
| 45 |
+
|
| 46 |
+
def __getitem__(self, entity):
|
| 47 |
+
key = self._get_key(entity)
|
| 48 |
+
parent = self._cache.get(key, None)
|
| 49 |
+
if parent is None:
|
| 50 |
+
# The bucket is initialized to support this usage:
|
| 51 |
+
# cache[key][subkey] = value
|
| 52 |
+
self._cache[key] = parent = {}
|
| 53 |
+
return parent
|
| 54 |
+
|
| 55 |
+
def __len__(self):
|
| 56 |
+
return len(self._cache)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class CodeObjectCache(_TransformedFnCache):
|
| 60 |
+
"""A function cache based on code objects.
|
| 61 |
+
|
| 62 |
+
Code objects are good proxies for the source code of a function.
|
| 63 |
+
|
| 64 |
+
This cache efficiently handles functions that share code objects, such as
|
| 65 |
+
functions defined in a loop, bound methods, etc.
|
| 66 |
+
|
| 67 |
+
The cache falls back to the function object, if it doesn't have a code object.
|
| 68 |
+
"""
|
| 69 |
+
|
| 70 |
+
def _get_key(self, entity):
|
| 71 |
+
if hasattr(entity, '__code__'):
|
| 72 |
+
return entity.__code__
|
| 73 |
+
else:
|
| 74 |
+
return entity
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class UnboundInstanceCache(_TransformedFnCache):
|
| 78 |
+
"""A function cache based on unbound function objects.
|
| 79 |
+
|
| 80 |
+
Using the function for the cache key allows efficient handling of object
|
| 81 |
+
methods.
|
| 82 |
+
|
| 83 |
+
Unlike the _CodeObjectCache, this discriminates between different functions
|
| 84 |
+
even if they have the same code. This is needed for decorators that may
|
| 85 |
+
masquerade as another function.
|
| 86 |
+
"""
|
| 87 |
+
|
| 88 |
+
def _get_key(self, entity):
|
| 89 |
+
if inspect.ismethod(entity):
|
| 90 |
+
return entity.__func__
|
| 91 |
+
return entity
|
| 92 |
+
|
| 93 |
+
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/cfg.py
ADDED
|
@@ -0,0 +1,976 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Control flow graph (CFG) structure for Python AST representation.
|
| 16 |
+
|
| 17 |
+
The CFG is a digraph with edges representing valid control flow. Each
|
| 18 |
+
node is associated with exactly one AST node, but not all AST nodes may have
|
| 19 |
+
a corresponding CFG counterpart.
|
| 20 |
+
|
| 21 |
+
Once built, the CFG itself is immutable, but the values it holds need not be;
|
| 22 |
+
they are usually annotated with information extracted by walking the graph.
|
| 23 |
+
|
| 24 |
+
Tip: Use `Graph.as_dot` to visualize the CFG using any DOT viewer.
|
| 25 |
+
|
| 26 |
+
Note: the CFG tries to include all code paths that MAY be taken, with a single
|
| 27 |
+
notable exception:
|
| 28 |
+
* function calls do not generate edges corresponding to exceptions they may
|
| 29 |
+
raise (i.e. a function call in the middle of a block does not return or jump
|
| 30 |
+
to any except or finally block)
|
| 31 |
+
TODO(mdan): Consider adding the edges above. They'd only add ~O(n) edges.
|
| 32 |
+
TODO(mdan): Alternatively, consider adding an edge from try to all its excepts.
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
# TODO(mdan): The notion of 'statements' below is inaccurate.
|
| 36 |
+
# They should rather be called 'block statements', because they include
|
| 37 |
+
# statements that may have a body, e.g. if and while.
|
| 38 |
+
|
| 39 |
+
import collections
|
| 40 |
+
import enum
|
| 41 |
+
import weakref
|
| 42 |
+
|
| 43 |
+
import astunparse
|
| 44 |
+
import gast
|
| 45 |
+
|
| 46 |
+
from tensorflow.python.autograph.pyct import anno
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class Node(object):
|
| 50 |
+
"""A node in the CFG.
|
| 51 |
+
|
| 52 |
+
Although new instances of this class are mutable, the objects that a user
|
| 53 |
+
finds in the CFG are typically not.
|
| 54 |
+
|
| 55 |
+
The nodes represent edges in the CFG graph, and maintain pointers to allow
|
| 56 |
+
efficient walking in both forward and reverse order. The following property
|
| 57 |
+
holds for all nodes: "child in node.next" iff "node in child.prev".
|
| 58 |
+
|
| 59 |
+
Attributes:
|
| 60 |
+
next: FrozenSet[Node, ...], the nodes that follow this node, in control flow
|
| 61 |
+
order
|
| 62 |
+
prev: FrozenSet[Node, ...], the nodes that precede this node, in reverse
|
| 63 |
+
control flow order
|
| 64 |
+
ast_node: ast.AST, the AST node corresponding to this CFG node
|
| 65 |
+
"""
|
| 66 |
+
|
| 67 |
+
def __init__(self, next_, prev, ast_node):
|
| 68 |
+
self.next = next_
|
| 69 |
+
self.prev = prev
|
| 70 |
+
self.ast_node = ast_node
|
| 71 |
+
|
| 72 |
+
def freeze(self):
|
| 73 |
+
self.next = frozenset(self.next)
|
| 74 |
+
# Assumption: All CFG nodes have identical life spans, because the graph
|
| 75 |
+
# owns them. Nodes should never be used outside the context of an existing
|
| 76 |
+
# graph.
|
| 77 |
+
self.prev = weakref.WeakSet(self.prev)
|
| 78 |
+
|
| 79 |
+
def __repr__(self):
|
| 80 |
+
if isinstance(self.ast_node, gast.FunctionDef):
|
| 81 |
+
return 'def %s' % self.ast_node.name
|
| 82 |
+
elif isinstance(self.ast_node, gast.ClassDef):
|
| 83 |
+
return 'class %s' % self.ast_node.name
|
| 84 |
+
elif isinstance(self.ast_node, gast.withitem):
|
| 85 |
+
# TODO(xjun): remove use of astunparse
|
| 86 |
+
return astunparse.unparse(self.ast_node.context_expr).strip()
|
| 87 |
+
return astunparse.unparse(self.ast_node).strip()
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
class Graph(
|
| 91 |
+
collections.namedtuple(
|
| 92 |
+
'Graph',
|
| 93 |
+
['entry', 'exit', 'error', 'index', 'stmt_prev', 'stmt_next'])):
|
| 94 |
+
"""A Control Flow Graph.
|
| 95 |
+
|
| 96 |
+
The CFG maintains an index to allow looking up a CFG node by the AST node to
|
| 97 |
+
which it is associated. The index can also be enumerated in top-down, depth
|
| 98 |
+
first order.
|
| 99 |
+
|
| 100 |
+
Walking the graph in forward or reverse order is supported by double
|
| 101 |
+
parent-child links.
|
| 102 |
+
|
| 103 |
+
Note: the error nodes are not wired to their corresponding finally guards,
|
| 104 |
+
because these are shared, and wiring them would create a reverse path from
|
| 105 |
+
normal control flow into the error nodes, which we want to avoid.
|
| 106 |
+
|
| 107 |
+
The graph also maintains edges corresponding to higher level statements
|
| 108 |
+
like for-else loops. A node is considered successor of a statement if there
|
| 109 |
+
is an edge from a node that is lexically a child of that statement to a node
|
| 110 |
+
that is not. Statement predecessors are analogously defined.
|
| 111 |
+
|
| 112 |
+
Attributes:
|
| 113 |
+
entry: Node, the entry node
|
| 114 |
+
exit: FrozenSet[Node, ...], the exit nodes
|
| 115 |
+
error: FrozenSet[Node, ...], nodes that exit due to an explicitly raised
|
| 116 |
+
error (errors propagated from function calls are not accounted)
|
| 117 |
+
index: Dict[ast.Node, Node], mapping AST nodes to the respective CFG node
|
| 118 |
+
stmt_prev: Dict[ast.Node, FrozenSet[Node, ...]], mapping statement AST nodes
|
| 119 |
+
to their predecessor CFG nodes
|
| 120 |
+
stmt_next: Dict[ast.Node, FrozenSet[Node, ...]], mapping statement AST nodes
|
| 121 |
+
to their successor CFG nodes
|
| 122 |
+
"""
|
| 123 |
+
|
| 124 |
+
def __repr__(self):
|
| 125 |
+
return self.as_dot()
|
| 126 |
+
|
| 127 |
+
def as_dot(self):
|
| 128 |
+
"""Print CFG in DOT format."""
|
| 129 |
+
result = 'digraph CFG {\n'
|
| 130 |
+
for node in self.index.values():
|
| 131 |
+
result += ' %s [label="%s"];\n' % (id(node), node)
|
| 132 |
+
for node in self.index.values():
|
| 133 |
+
for next_ in node.next:
|
| 134 |
+
result += ' %s -> %s;\n' % (id(node), id(next_))
|
| 135 |
+
result += '}'
|
| 136 |
+
return result
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
class _WalkMode(enum.Enum):
|
| 140 |
+
FORWARD = 1
|
| 141 |
+
REVERSE = 2
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
# TODO(mdan): Rename to DataFlowAnalyzer.
|
| 145 |
+
# TODO(mdan): Consider specializations that use gen/kill/transfer abstractions.
|
| 146 |
+
class GraphVisitor(object):
|
| 147 |
+
"""Base class for a CFG visitors.
|
| 148 |
+
|
| 149 |
+
This implementation is not thread safe.
|
| 150 |
+
|
| 151 |
+
The visitor has some facilities to simplify dataflow analyses. In particular,
|
| 152 |
+
it allows revisiting the nodes at the decision of the subclass. This can be
|
| 153 |
+
used to visit the graph until the state reaches a fixed point.
|
| 154 |
+
|
| 155 |
+
For more details on dataflow analysis, see
|
| 156 |
+
https://www.seas.harvard.edu/courses/cs252/2011sp/slides/Lec02-Dataflow.pdf
|
| 157 |
+
|
| 158 |
+
Note: the literature generally suggests visiting successor nodes only when the
|
| 159 |
+
state of the current node changed, regardless of whether that successor has
|
| 160 |
+
ever been visited. This implementation visits every successor at least once.
|
| 161 |
+
|
| 162 |
+
Attributes:
|
| 163 |
+
graph: Graph
|
| 164 |
+
in_: Dict[Node, Any], stores node-keyed state during a visit
|
| 165 |
+
out: Dict[Node, Any], stores node-keyed state during a visit
|
| 166 |
+
"""
|
| 167 |
+
|
| 168 |
+
def __init__(self, graph):
|
| 169 |
+
self.graph = graph
|
| 170 |
+
self.reset()
|
| 171 |
+
|
| 172 |
+
def init_state(self, node):
|
| 173 |
+
"""State initialization function.
|
| 174 |
+
|
| 175 |
+
Optional to overload.
|
| 176 |
+
|
| 177 |
+
An in/out state slot will be created for each node in the graph. Subclasses
|
| 178 |
+
must overload this to control what that is initialized to.
|
| 179 |
+
|
| 180 |
+
Args:
|
| 181 |
+
node: Node
|
| 182 |
+
"""
|
| 183 |
+
raise NotImplementedError('Subclasses must implement this.')
|
| 184 |
+
|
| 185 |
+
# TODO(mdan): Rename to flow?
|
| 186 |
+
def visit_node(self, node):
|
| 187 |
+
"""Visitor function.
|
| 188 |
+
|
| 189 |
+
Args:
|
| 190 |
+
node: Node
|
| 191 |
+
|
| 192 |
+
Returns:
|
| 193 |
+
bool, whether the node should be revisited; subclasses can visit every
|
| 194 |
+
reachable node exactly once by always returning False
|
| 195 |
+
"""
|
| 196 |
+
raise NotImplementedError('Subclasses must implement this.')
|
| 197 |
+
|
| 198 |
+
def reset(self):
|
| 199 |
+
self.in_ = {
|
| 200 |
+
node: self.init_state(node) for node in self.graph.index.values()
|
| 201 |
+
}
|
| 202 |
+
self.out = {
|
| 203 |
+
node: self.init_state(node) for node in self.graph.index.values()
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
def can_ignore(self, node):
|
| 207 |
+
"""Returns True if the node can safely be assumed not to touch variables."""
|
| 208 |
+
ast_node = node.ast_node
|
| 209 |
+
if anno.hasanno(ast_node, anno.Basic.SKIP_PROCESSING):
|
| 210 |
+
return True
|
| 211 |
+
return isinstance(ast_node,
|
| 212 |
+
(gast.Break, gast.Continue, gast.Raise, gast.Pass))
|
| 213 |
+
|
| 214 |
+
def _visit_internal(self, mode):
|
| 215 |
+
"""Visits the CFG, breadth-first."""
|
| 216 |
+
assert mode in (_WalkMode.FORWARD, _WalkMode.REVERSE)
|
| 217 |
+
if mode == _WalkMode.FORWARD:
|
| 218 |
+
open_ = [self.graph.entry]
|
| 219 |
+
elif mode == _WalkMode.REVERSE:
|
| 220 |
+
open_ = list(self.graph.exit)
|
| 221 |
+
closed = set()
|
| 222 |
+
|
| 223 |
+
while open_:
|
| 224 |
+
node = open_.pop(0)
|
| 225 |
+
closed.add(node)
|
| 226 |
+
|
| 227 |
+
should_revisit = self.visit_node(node)
|
| 228 |
+
|
| 229 |
+
if mode == _WalkMode.FORWARD:
|
| 230 |
+
children = node.next
|
| 231 |
+
elif mode == _WalkMode.REVERSE:
|
| 232 |
+
children = node.prev
|
| 233 |
+
|
| 234 |
+
for next_ in children:
|
| 235 |
+
if should_revisit or next_ not in closed:
|
| 236 |
+
open_.append(next_)
|
| 237 |
+
|
| 238 |
+
def visit_forward(self):
|
| 239 |
+
self._visit_internal(_WalkMode.FORWARD)
|
| 240 |
+
|
| 241 |
+
def visit_reverse(self):
|
| 242 |
+
self._visit_internal(_WalkMode.REVERSE)
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
class GraphBuilder(object):
|
| 246 |
+
"""Builder that constructs a CFG from a given AST.
|
| 247 |
+
|
| 248 |
+
This GraphBuilder facilitates constructing the DAG that forms the CFG when
|
| 249 |
+
nodes
|
| 250 |
+
are supplied in lexical order (i.e., top-down, depth first). Under these
|
| 251 |
+
conditions, it supports building patterns found in typical structured
|
| 252 |
+
programs.
|
| 253 |
+
|
| 254 |
+
This builder ignores the flow generated by exceptions, which are assumed to
|
| 255 |
+
always be catastrophic and present purely for diagnostic purposes (e.g. to
|
| 256 |
+
print debug information). Statements like raise and try/catch sections are
|
| 257 |
+
allowed and will generate control flow edges, but ordinary statements are
|
| 258 |
+
assumed not to raise exceptions.
|
| 259 |
+
|
| 260 |
+
Finally sections are also correctly interleaved between break/continue/return
|
| 261 |
+
nodes and their subsequent statements.
|
| 262 |
+
|
| 263 |
+
Important concepts:
|
| 264 |
+
* nodes - nodes refer to CFG nodes; AST nodes are qualified explicitly
|
| 265 |
+
* leaf set - since the graph is constructed gradually, a leaf set maintains
|
| 266 |
+
the CFG nodes that will precede the node that the builder expects to
|
| 267 |
+
receive next; when an ordinary node is added, it is connected to the
|
| 268 |
+
existing leaves and it in turn becomes the new leaf
|
| 269 |
+
* jump nodes - nodes that should generate edges other than what
|
| 270 |
+
ordinary nodes would; these correspond to break, continue and return
|
| 271 |
+
statements
|
| 272 |
+
* sections - logical delimiters for subgraphs that require special
|
| 273 |
+
edges; there are various types of nodes, each admitting various
|
| 274 |
+
types of jump nodes; sections are identified by their corresponding AST
|
| 275 |
+
node
|
| 276 |
+
"""
|
| 277 |
+
|
| 278 |
+
# TODO(mdan): Perhaps detail this in a markdown doc.
|
| 279 |
+
# TODO(mdan): Add exception support.
|
| 280 |
+
|
| 281 |
+
def __init__(self, parent_ast_node):
|
| 282 |
+
self.reset()
|
| 283 |
+
self.parent = parent_ast_node
|
| 284 |
+
|
| 285 |
+
def reset(self):
|
| 286 |
+
"""Resets the state of this factory."""
|
| 287 |
+
self.head = None
|
| 288 |
+
self.errors = set()
|
| 289 |
+
self.node_index = {}
|
| 290 |
+
|
| 291 |
+
# TODO(mdan): Too many primitives. Use classes.
|
| 292 |
+
self.leaves = set()
|
| 293 |
+
|
| 294 |
+
# Note: This mechanism requires that nodes are added in lexical order (top
|
| 295 |
+
# to bottom, depth first).
|
| 296 |
+
self.active_stmts = set()
|
| 297 |
+
self.owners = {} # type: Set[any]
|
| 298 |
+
self.forward_edges = set() # type: Tuple[Node, Node] # (from, to)
|
| 299 |
+
|
| 300 |
+
self.finally_sections = {}
|
| 301 |
+
# Dict values represent (entry, exits)
|
| 302 |
+
self.finally_section_subgraphs = {
|
| 303 |
+
} # type: Dict[ast.AST, Tuple[Node, Set[Node]]]
|
| 304 |
+
# Whether the guard section can be reached from the statement that precedes
|
| 305 |
+
# it.
|
| 306 |
+
self.finally_section_has_direct_flow = {}
|
| 307 |
+
# Finally sections that await their first node.
|
| 308 |
+
self.pending_finally_sections = set()
|
| 309 |
+
|
| 310 |
+
# Exit jumps keyed by the section they affect.
|
| 311 |
+
self.exits = {}
|
| 312 |
+
|
| 313 |
+
# The entry of loop sections, keyed by the section.
|
| 314 |
+
self.section_entry = {}
|
| 315 |
+
# Continue jumps keyed by the section they affect.
|
| 316 |
+
self.continues = {}
|
| 317 |
+
|
| 318 |
+
# Raise jumps keyed by the except section guarding them.
|
| 319 |
+
self.raises = {}
|
| 320 |
+
|
| 321 |
+
# The entry of conditional sections, keyed by the section.
|
| 322 |
+
self.cond_entry = {}
|
| 323 |
+
# Lists of leaf nodes corresponding to each branch in the section.
|
| 324 |
+
self.cond_leaves = {}
|
| 325 |
+
|
| 326 |
+
def _connect_nodes(self, first, second):
|
| 327 |
+
"""Connects nodes to signify that control flows from first to second.
|
| 328 |
+
|
| 329 |
+
Args:
|
| 330 |
+
first: Union[Set[Node, ...], Node]
|
| 331 |
+
second: Node
|
| 332 |
+
"""
|
| 333 |
+
if isinstance(first, Node):
|
| 334 |
+
first.next.add(second)
|
| 335 |
+
second.prev.add(first)
|
| 336 |
+
self.forward_edges.add((first, second))
|
| 337 |
+
else:
|
| 338 |
+
for node in first:
|
| 339 |
+
self._connect_nodes(node, second)
|
| 340 |
+
|
| 341 |
+
def _add_new_node(self, ast_node):
|
| 342 |
+
"""Grows the graph by adding a CFG node following the current leaves."""
|
| 343 |
+
if ast_node in self.node_index:
|
| 344 |
+
raise ValueError('%s added twice' % ast_node)
|
| 345 |
+
# Assumption: All CFG nodes have identical life spans, because the graph
|
| 346 |
+
# owns them. Nodes should never be used outside the context of an existing
|
| 347 |
+
# graph.
|
| 348 |
+
node = Node(next_=set(), prev=weakref.WeakSet(), ast_node=ast_node)
|
| 349 |
+
self.node_index[ast_node] = node
|
| 350 |
+
self.owners[node] = frozenset(self.active_stmts)
|
| 351 |
+
|
| 352 |
+
if self.head is None:
|
| 353 |
+
self.head = node
|
| 354 |
+
|
| 355 |
+
for leaf in self.leaves:
|
| 356 |
+
self._connect_nodes(leaf, node)
|
| 357 |
+
|
| 358 |
+
# If any finally section awaits its first node, populate it.
|
| 359 |
+
for section_id in self.pending_finally_sections:
|
| 360 |
+
self.finally_section_subgraphs[section_id][0] = node
|
| 361 |
+
self.pending_finally_sections = set()
|
| 362 |
+
|
| 363 |
+
return node
|
| 364 |
+
|
| 365 |
+
def begin_statement(self, stmt):
|
| 366 |
+
"""Marks the beginning of a statement.
|
| 367 |
+
|
| 368 |
+
Args:
|
| 369 |
+
stmt: Hashable, a key by which the statement can be identified in the
|
| 370 |
+
CFG's stmt_prev and stmt_next attributes
|
| 371 |
+
"""
|
| 372 |
+
self.active_stmts.add(stmt)
|
| 373 |
+
|
| 374 |
+
def end_statement(self, stmt):
|
| 375 |
+
"""Marks the end of a statement.
|
| 376 |
+
|
| 377 |
+
Args:
|
| 378 |
+
stmt: Hashable, a key by which the statement can be identified in the
|
| 379 |
+
CFG's stmt_prev and stmt_next attributes; must match a key previously
|
| 380 |
+
passed to begin_statement.
|
| 381 |
+
"""
|
| 382 |
+
self.active_stmts.remove(stmt)
|
| 383 |
+
|
| 384 |
+
def add_ordinary_node(self, ast_node):
|
| 385 |
+
"""Grows the graph by adding an ordinary CFG node.
|
| 386 |
+
|
| 387 |
+
Ordinary nodes are followed by the next node, in lexical order, that is,
|
| 388 |
+
they become the new leaf set.
|
| 389 |
+
|
| 390 |
+
Args:
|
| 391 |
+
ast_node: ast.AST
|
| 392 |
+
|
| 393 |
+
Returns:
|
| 394 |
+
Node
|
| 395 |
+
"""
|
| 396 |
+
node = self._add_new_node(ast_node)
|
| 397 |
+
self.leaves = set((node,))
|
| 398 |
+
return node
|
| 399 |
+
|
| 400 |
+
def _add_jump_node(self, ast_node, guards):
|
| 401 |
+
"""Grows the graph by adding a jump node.
|
| 402 |
+
|
| 403 |
+
Jump nodes are added to the current leaf set, and the leaf set becomes
|
| 404 |
+
empty. If the jump node is the last in a cond section, then it may be added
|
| 405 |
+
back to the leaf set by a separate mechanism.
|
| 406 |
+
|
| 407 |
+
Args:
|
| 408 |
+
ast_node: ast.AST
|
| 409 |
+
guards: Tuple[ast.AST, ...], the finally sections active for this node
|
| 410 |
+
|
| 411 |
+
Returns:
|
| 412 |
+
Node
|
| 413 |
+
"""
|
| 414 |
+
node = self._add_new_node(ast_node)
|
| 415 |
+
self.leaves = set()
|
| 416 |
+
# The guards themselves may not yet be complete, and will be wired later.
|
| 417 |
+
self.finally_sections[node] = guards
|
| 418 |
+
return node
|
| 419 |
+
|
| 420 |
+
def _connect_jump_to_finally_sections(self, node):
|
| 421 |
+
"""Connects a jump node to the finally sections protecting it."""
|
| 422 |
+
cursor = set((node,))
|
| 423 |
+
if node not in self.finally_sections:
|
| 424 |
+
return cursor
|
| 425 |
+
for guard_section_id in self.finally_sections[node]:
|
| 426 |
+
guard_begin, guard_ends = self.finally_section_subgraphs[guard_section_id]
|
| 427 |
+
self._connect_nodes(cursor, guard_begin)
|
| 428 |
+
cursor = guard_ends
|
| 429 |
+
del self.finally_sections[node]
|
| 430 |
+
# TODO(mdan): Should garbage-collect finally_section_subgraphs.
|
| 431 |
+
return cursor
|
| 432 |
+
|
| 433 |
+
def add_exit_node(self, ast_node, section_id, guards):
|
| 434 |
+
"""Grows the graph by adding an exit node.
|
| 435 |
+
|
| 436 |
+
This node becomes an exit for the current section.
|
| 437 |
+
|
| 438 |
+
Args:
|
| 439 |
+
ast_node: ast.AST
|
| 440 |
+
section_id: Hashable, the node for which ast_node should be considered to
|
| 441 |
+
be an exit node
|
| 442 |
+
guards: Tuple[ast.AST, ...], the finally sections that guard ast_node
|
| 443 |
+
|
| 444 |
+
Returns:
|
| 445 |
+
Node
|
| 446 |
+
"""
|
| 447 |
+
node = self._add_jump_node(ast_node, guards)
|
| 448 |
+
self.exits[section_id].add(node)
|
| 449 |
+
return node
|
| 450 |
+
|
| 451 |
+
def add_continue_node(self, ast_node, section_id, guards):
|
| 452 |
+
"""Grows the graph by adding a reentry node.
|
| 453 |
+
|
| 454 |
+
This node causes control flow to go back to the loop section's entry.
|
| 455 |
+
|
| 456 |
+
Args:
|
| 457 |
+
ast_node: ast.AST
|
| 458 |
+
section_id: Hashable, the node for which ast_node should be considered to
|
| 459 |
+
be an exit node
|
| 460 |
+
guards: Tuple[ast.AST, ...], the finally sections that guard ast_node
|
| 461 |
+
"""
|
| 462 |
+
node = self._add_jump_node(ast_node, guards)
|
| 463 |
+
self.continues[section_id].add(node)
|
| 464 |
+
|
| 465 |
+
def connect_raise_node(self, node, except_guards):
|
| 466 |
+
"""Adds extra connection between a raise node and containing except guards.
|
| 467 |
+
|
| 468 |
+
The node is a graph node, not an ast node.
|
| 469 |
+
|
| 470 |
+
Args:
|
| 471 |
+
node: Node
|
| 472 |
+
except_guards: Tuple[ast.AST, ...], the except sections that guard node
|
| 473 |
+
"""
|
| 474 |
+
for guard in except_guards:
|
| 475 |
+
if guard in self.raises:
|
| 476 |
+
self.raises[guard].append(node)
|
| 477 |
+
else:
|
| 478 |
+
self.raises[guard] = [node]
|
| 479 |
+
|
| 480 |
+
def enter_section(self, section_id):
|
| 481 |
+
"""Enters a regular section.
|
| 482 |
+
|
| 483 |
+
Regular sections admit exit jumps, which end the section.
|
| 484 |
+
|
| 485 |
+
Args:
|
| 486 |
+
section_id: Hashable, the same node that will be used in calls to the
|
| 487 |
+
ast_node arg passed to add_exit_node
|
| 488 |
+
"""
|
| 489 |
+
assert section_id not in self.exits
|
| 490 |
+
self.exits[section_id] = set()
|
| 491 |
+
|
| 492 |
+
def exit_section(self, section_id):
|
| 493 |
+
"""Exits a regular section."""
|
| 494 |
+
|
| 495 |
+
# Exits are jump nodes, which may be protected.
|
| 496 |
+
for exit_ in self.exits[section_id]:
|
| 497 |
+
self.leaves |= self._connect_jump_to_finally_sections(exit_)
|
| 498 |
+
|
| 499 |
+
del self.exits[section_id]
|
| 500 |
+
|
| 501 |
+
def enter_loop_section(self, section_id, entry_node):
|
| 502 |
+
"""Enters a loop section.
|
| 503 |
+
|
| 504 |
+
Loop sections define an entry node. The end of the section always flows back
|
| 505 |
+
to the entry node. These admit continue jump nodes which also flow to the
|
| 506 |
+
entry node.
|
| 507 |
+
|
| 508 |
+
Args:
|
| 509 |
+
section_id: Hashable, the same node that will be used in calls to the
|
| 510 |
+
ast_node arg passed to add_continue_node
|
| 511 |
+
entry_node: ast.AST, the entry node into the loop (e.g. the test node for
|
| 512 |
+
while loops)
|
| 513 |
+
"""
|
| 514 |
+
assert section_id not in self.section_entry
|
| 515 |
+
assert section_id not in self.continues
|
| 516 |
+
self.continues[section_id] = set()
|
| 517 |
+
node = self.add_ordinary_node(entry_node)
|
| 518 |
+
self.section_entry[section_id] = node
|
| 519 |
+
|
| 520 |
+
def exit_loop_section(self, section_id):
|
| 521 |
+
"""Exits a loop section."""
|
| 522 |
+
self._connect_nodes(self.leaves, self.section_entry[section_id])
|
| 523 |
+
|
| 524 |
+
# continues are jump nodes, which may be protected.
|
| 525 |
+
for reentry in self.continues[section_id]:
|
| 526 |
+
guard_ends = self._connect_jump_to_finally_sections(reentry)
|
| 527 |
+
self._connect_nodes(guard_ends, self.section_entry[section_id])
|
| 528 |
+
|
| 529 |
+
# Loop nodes always loop back.
|
| 530 |
+
self.leaves = set((self.section_entry[section_id],))
|
| 531 |
+
|
| 532 |
+
del self.continues[section_id]
|
| 533 |
+
del self.section_entry[section_id]
|
| 534 |
+
|
| 535 |
+
def enter_cond_section(self, section_id):
|
| 536 |
+
"""Enters a conditional section.
|
| 537 |
+
|
| 538 |
+
Conditional sections define an entry node, and one or more branches.
|
| 539 |
+
|
| 540 |
+
Args:
|
| 541 |
+
section_id: Hashable, the same node that will be used in calls to the
|
| 542 |
+
section_id arg passed to new_cond_branch
|
| 543 |
+
"""
|
| 544 |
+
|
| 545 |
+
assert section_id not in self.cond_entry
|
| 546 |
+
assert section_id not in self.cond_leaves
|
| 547 |
+
self.cond_leaves[section_id] = []
|
| 548 |
+
|
| 549 |
+
def new_cond_branch(self, section_id):
|
| 550 |
+
"""Begins a new branch in a cond section."""
|
| 551 |
+
assert section_id in self.cond_leaves
|
| 552 |
+
|
| 553 |
+
if section_id in self.cond_entry:
|
| 554 |
+
# Subsequent splits move back to the split point, and memorize the
|
| 555 |
+
# current leaves.
|
| 556 |
+
self.cond_leaves[section_id].append(self.leaves)
|
| 557 |
+
self.leaves = self.cond_entry[section_id]
|
| 558 |
+
else:
|
| 559 |
+
# If this is the first time we split a section, just remember the split
|
| 560 |
+
# point.
|
| 561 |
+
self.cond_entry[section_id] = self.leaves
|
| 562 |
+
|
| 563 |
+
def exit_cond_section(self, section_id):
|
| 564 |
+
"""Exits a conditional section."""
|
| 565 |
+
for split in self.cond_leaves[section_id]:
|
| 566 |
+
self.leaves |= split
|
| 567 |
+
del self.cond_entry[section_id]
|
| 568 |
+
del self.cond_leaves[section_id]
|
| 569 |
+
|
| 570 |
+
def enter_except_section(self, section_id):
|
| 571 |
+
"""Enters an except section."""
|
| 572 |
+
if section_id in self.raises:
|
| 573 |
+
self.leaves.update(self.raises[section_id])
|
| 574 |
+
|
| 575 |
+
def enter_finally_section(self, section_id):
|
| 576 |
+
"""Enters a finally section."""
|
| 577 |
+
# TODO(mdan): This, not the caller, should track the active sections.
|
| 578 |
+
self.finally_section_subgraphs[section_id] = [None, None]
|
| 579 |
+
if self.leaves:
|
| 580 |
+
self.finally_section_has_direct_flow[section_id] = True
|
| 581 |
+
else:
|
| 582 |
+
self.finally_section_has_direct_flow[section_id] = False
|
| 583 |
+
self.pending_finally_sections.add(section_id)
|
| 584 |
+
|
| 585 |
+
def exit_finally_section(self, section_id):
|
| 586 |
+
"""Exits a finally section."""
|
| 587 |
+
assert section_id not in self.pending_finally_sections, 'Empty finally?'
|
| 588 |
+
self.finally_section_subgraphs[section_id][1] = self.leaves
|
| 589 |
+
# If the guard can only be reached by a jump, then it will not flow
|
| 590 |
+
# into the statement that follows it.
|
| 591 |
+
if not self.finally_section_has_direct_flow[section_id]:
|
| 592 |
+
self.leaves = set()
|
| 593 |
+
del self.finally_section_has_direct_flow[section_id]
|
| 594 |
+
|
| 595 |
+
def build(self):
|
| 596 |
+
"""Returns the CFG accumulated so far and resets the builder.
|
| 597 |
+
|
| 598 |
+
Returns:
|
| 599 |
+
Graph
|
| 600 |
+
"""
|
| 601 |
+
# Freeze the nodes.
|
| 602 |
+
for node in self.node_index.values():
|
| 603 |
+
node.freeze()
|
| 604 |
+
|
| 605 |
+
# Build the statement edges.
|
| 606 |
+
stmt_next = {}
|
| 607 |
+
stmt_prev = {}
|
| 608 |
+
|
| 609 |
+
for node in self.node_index.values():
|
| 610 |
+
for stmt in self.owners[node]:
|
| 611 |
+
if stmt not in stmt_prev:
|
| 612 |
+
stmt_prev[stmt] = set()
|
| 613 |
+
if stmt not in stmt_next:
|
| 614 |
+
stmt_next[stmt] = set()
|
| 615 |
+
|
| 616 |
+
for first, second in self.forward_edges:
|
| 617 |
+
stmts_exited = self.owners[first] - self.owners[second]
|
| 618 |
+
for stmt in stmts_exited:
|
| 619 |
+
stmt_next[stmt].add(second)
|
| 620 |
+
stmts_entered = self.owners[second] - self.owners[first]
|
| 621 |
+
for stmt in stmts_entered:
|
| 622 |
+
stmt_prev[stmt].add(first)
|
| 623 |
+
for stmt in stmt_next:
|
| 624 |
+
stmt_next[stmt] = frozenset(stmt_next[stmt])
|
| 625 |
+
for stmt in stmt_prev:
|
| 626 |
+
stmt_prev[stmt] = frozenset(stmt_prev[stmt])
|
| 627 |
+
|
| 628 |
+
# Construct the final graph object.
|
| 629 |
+
result = Graph(
|
| 630 |
+
entry=self.head,
|
| 631 |
+
exit=self.leaves,
|
| 632 |
+
error=self.errors,
|
| 633 |
+
index=self.node_index,
|
| 634 |
+
stmt_prev=stmt_prev,
|
| 635 |
+
stmt_next=stmt_next)
|
| 636 |
+
|
| 637 |
+
# Reset the state.
|
| 638 |
+
self.reset()
|
| 639 |
+
|
| 640 |
+
return result
|
| 641 |
+
|
| 642 |
+
|
| 643 |
+
class AstToCfg(gast.NodeVisitor):
|
| 644 |
+
"""Converts an AST to CFGs.
|
| 645 |
+
|
| 646 |
+
A separate CFG will be constructed for each function.
|
| 647 |
+
"""
|
| 648 |
+
|
| 649 |
+
def __init__(self):
|
| 650 |
+
super(AstToCfg, self).__init__()
|
| 651 |
+
|
| 652 |
+
self.builder_stack = []
|
| 653 |
+
self.builder = None
|
| 654 |
+
self.cfgs = {}
|
| 655 |
+
|
| 656 |
+
self.lexical_scopes = []
|
| 657 |
+
|
| 658 |
+
def _enter_lexical_scope(self, node):
|
| 659 |
+
self.lexical_scopes.append(node)
|
| 660 |
+
|
| 661 |
+
def _exit_lexical_scope(self, node):
|
| 662 |
+
leaving_node = self.lexical_scopes.pop()
|
| 663 |
+
assert node == leaving_node
|
| 664 |
+
|
| 665 |
+
def _get_enclosing_finally_scopes(self, stop_at):
|
| 666 |
+
included = []
|
| 667 |
+
for node in reversed(self.lexical_scopes):
|
| 668 |
+
if isinstance(node, gast.Try) and node.finalbody:
|
| 669 |
+
included.append(node)
|
| 670 |
+
if isinstance(node, stop_at):
|
| 671 |
+
return node, included
|
| 672 |
+
return None, included
|
| 673 |
+
|
| 674 |
+
def _get_enclosing_except_scopes(self, stop_at):
|
| 675 |
+
included = []
|
| 676 |
+
for node in reversed(self.lexical_scopes):
|
| 677 |
+
if isinstance(node, gast.Try) and node.handlers:
|
| 678 |
+
included.extend(node.handlers)
|
| 679 |
+
if isinstance(node, stop_at):
|
| 680 |
+
break
|
| 681 |
+
return included
|
| 682 |
+
|
| 683 |
+
def _process_basic_statement(self, node):
|
| 684 |
+
self.generic_visit(node)
|
| 685 |
+
self.builder.add_ordinary_node(node)
|
| 686 |
+
|
| 687 |
+
def _process_exit_statement(self,
|
| 688 |
+
node,
|
| 689 |
+
exits_nodes_of_type,
|
| 690 |
+
may_exit_via_except=False):
|
| 691 |
+
self.generic_visit(node)
|
| 692 |
+
# Note: this is safe because we process functions separately.
|
| 693 |
+
try_node, guards = self._get_enclosing_finally_scopes(exits_nodes_of_type)
|
| 694 |
+
assert try_node is not None, '{} that is not enclosed by any of {}'.format(
|
| 695 |
+
node, exits_nodes_of_type)
|
| 696 |
+
|
| 697 |
+
node = self.builder.add_exit_node(node, try_node, guards)
|
| 698 |
+
|
| 699 |
+
if may_exit_via_except:
|
| 700 |
+
except_guards = self._get_enclosing_except_scopes(exits_nodes_of_type)
|
| 701 |
+
self.builder.connect_raise_node(node, except_guards)
|
| 702 |
+
|
| 703 |
+
def _process_continue_statement(self, node, *loops_to_nodes_of_type):
|
| 704 |
+
# Note: this is safe because we process functions separately.
|
| 705 |
+
try_node, guards = self._get_enclosing_finally_scopes(
|
| 706 |
+
tuple(loops_to_nodes_of_type))
|
| 707 |
+
if try_node is None:
|
| 708 |
+
raise ValueError('%s that is not enclosed by any of %s' %
|
| 709 |
+
(node, loops_to_nodes_of_type))
|
| 710 |
+
self.builder.add_continue_node(node, try_node, guards)
|
| 711 |
+
|
| 712 |
+
def visit_ClassDef(self, node):
|
| 713 |
+
# We also keep the ClassDef node in the CFG, since it technically is a
|
| 714 |
+
# statement.
|
| 715 |
+
# For example, this is legal and allows executing user code:
|
| 716 |
+
#
|
| 717 |
+
# class Foo(bar()):
|
| 718 |
+
# pass
|
| 719 |
+
#
|
| 720 |
+
# It also has a scope:
|
| 721 |
+
#
|
| 722 |
+
# class Bar(object):
|
| 723 |
+
# a = 1
|
| 724 |
+
if self.builder is None:
|
| 725 |
+
self.generic_visit(node)
|
| 726 |
+
return
|
| 727 |
+
|
| 728 |
+
self.builder.add_ordinary_node(node)
|
| 729 |
+
|
| 730 |
+
self.builder_stack.append(self.builder)
|
| 731 |
+
self.builder = GraphBuilder(node)
|
| 732 |
+
self._enter_lexical_scope(node)
|
| 733 |
+
|
| 734 |
+
self._process_basic_statement(node)
|
| 735 |
+
|
| 736 |
+
self._exit_lexical_scope(node)
|
| 737 |
+
# TODO(mdan): Track the CFG local to the class definition as well?
|
| 738 |
+
self.builder = self.builder_stack.pop()
|
| 739 |
+
|
| 740 |
+
def _process_function_def(self, node, is_lambda):
|
| 741 |
+
# The function body is stored in a separate graph, because function
|
| 742 |
+
# definitions have effects very different from function calls.
|
| 743 |
+
if self.builder is not None:
|
| 744 |
+
self.builder.add_ordinary_node(node)
|
| 745 |
+
|
| 746 |
+
self.builder_stack.append(self.builder)
|
| 747 |
+
self.builder = GraphBuilder(node)
|
| 748 |
+
|
| 749 |
+
self._enter_lexical_scope(node)
|
| 750 |
+
self.builder.enter_section(node)
|
| 751 |
+
|
| 752 |
+
self._process_basic_statement(node.args)
|
| 753 |
+
if is_lambda:
|
| 754 |
+
self._process_exit_statement(node.body, (gast.Lambda,))
|
| 755 |
+
else:
|
| 756 |
+
for stmt in node.body:
|
| 757 |
+
self.visit(stmt)
|
| 758 |
+
|
| 759 |
+
self.builder.exit_section(node)
|
| 760 |
+
self._exit_lexical_scope(node)
|
| 761 |
+
|
| 762 |
+
self.cfgs[node] = self.builder.build()
|
| 763 |
+
self.builder = self.builder_stack.pop()
|
| 764 |
+
|
| 765 |
+
def visit_FunctionDef(self, node):
|
| 766 |
+
self._process_function_def(node, is_lambda=False)
|
| 767 |
+
|
| 768 |
+
def visit_Lambda(self, node):
|
| 769 |
+
self._process_function_def(node, is_lambda=True)
|
| 770 |
+
|
| 771 |
+
def visit_Return(self, node):
|
| 772 |
+
self._process_exit_statement(node, (gast.FunctionDef,))
|
| 773 |
+
|
| 774 |
+
def visit_Import(self, node):
|
| 775 |
+
self._process_basic_statement(node)
|
| 776 |
+
|
| 777 |
+
def visit_ImportFrom(self, node):
|
| 778 |
+
self._process_basic_statement(node)
|
| 779 |
+
|
| 780 |
+
def visit_Expr(self, node):
|
| 781 |
+
self._process_basic_statement(node)
|
| 782 |
+
|
| 783 |
+
def visit_NamedExpr(self, node):
|
| 784 |
+
# TODO(yileiyang): Add a test case once we have a newer astunparse version.
|
| 785 |
+
# NamedExpr was introduced in Python 3.8 and supported in gast 0.5.1+.
|
| 786 |
+
self._process_basic_statement(node)
|
| 787 |
+
|
| 788 |
+
def visit_Assign(self, node):
|
| 789 |
+
self._process_basic_statement(node)
|
| 790 |
+
|
| 791 |
+
def visit_AnnAssign(self, node):
|
| 792 |
+
self._process_basic_statement(node)
|
| 793 |
+
|
| 794 |
+
def visit_AugAssign(self, node):
|
| 795 |
+
self._process_basic_statement(node)
|
| 796 |
+
|
| 797 |
+
def visit_Pass(self, node):
|
| 798 |
+
self._process_basic_statement(node)
|
| 799 |
+
|
| 800 |
+
def visit_Global(self, node):
|
| 801 |
+
self._process_basic_statement(node)
|
| 802 |
+
|
| 803 |
+
def visit_Nonlocal(self, node):
|
| 804 |
+
self._process_basic_statement(node)
|
| 805 |
+
|
| 806 |
+
def visit_Print(self, node):
|
| 807 |
+
self._process_basic_statement(node)
|
| 808 |
+
|
| 809 |
+
def visit_Raise(self, node):
|
| 810 |
+
self._process_exit_statement(
|
| 811 |
+
node, (gast.FunctionDef,), may_exit_via_except=True)
|
| 812 |
+
self.builder.errors.add(node)
|
| 813 |
+
|
| 814 |
+
def visit_Assert(self, node):
|
| 815 |
+
# Ignoring the effect of exceptions.
|
| 816 |
+
self._process_basic_statement(node)
|
| 817 |
+
|
| 818 |
+
def visit_Delete(self, node):
|
| 819 |
+
self._process_basic_statement(node)
|
| 820 |
+
|
| 821 |
+
def visit_If(self, node):
|
| 822 |
+
# No need to track ifs as lexical scopes, for now.
|
| 823 |
+
# Lexical scopes are generally tracked in order to be able to resolve the
|
| 824 |
+
# targets of jump statements like break/continue/etc. Since there is no
|
| 825 |
+
# statement that can interrupt a conditional, we don't need to track their
|
| 826 |
+
# lexical scope. That may change in the future.
|
| 827 |
+
self.builder.begin_statement(node)
|
| 828 |
+
|
| 829 |
+
self.builder.enter_cond_section(node)
|
| 830 |
+
self._process_basic_statement(node.test)
|
| 831 |
+
|
| 832 |
+
self.builder.new_cond_branch(node)
|
| 833 |
+
for stmt in node.body:
|
| 834 |
+
self.visit(stmt)
|
| 835 |
+
|
| 836 |
+
self.builder.new_cond_branch(node)
|
| 837 |
+
for stmt in node.orelse:
|
| 838 |
+
self.visit(stmt)
|
| 839 |
+
|
| 840 |
+
self.builder.exit_cond_section(node)
|
| 841 |
+
self.builder.end_statement(node)
|
| 842 |
+
|
| 843 |
+
def visit_While(self, node):
|
| 844 |
+
self.builder.begin_statement(node)
|
| 845 |
+
self._enter_lexical_scope(node)
|
| 846 |
+
|
| 847 |
+
self.builder.enter_section(node)
|
| 848 |
+
|
| 849 |
+
self.generic_visit(node.test)
|
| 850 |
+
self.builder.enter_loop_section(node, node.test)
|
| 851 |
+
for stmt in node.body:
|
| 852 |
+
self.visit(stmt)
|
| 853 |
+
self.builder.exit_loop_section(node)
|
| 854 |
+
|
| 855 |
+
# Note: although the orelse is technically part of the loop node,
|
| 856 |
+
# the statements inside it don't affect the loop itself. For example, a
|
| 857 |
+
# break in the loop's orelse will not affect the loop itself.
|
| 858 |
+
self._exit_lexical_scope(node)
|
| 859 |
+
|
| 860 |
+
for stmt in node.orelse:
|
| 861 |
+
self.visit(stmt)
|
| 862 |
+
|
| 863 |
+
self.builder.exit_section(node)
|
| 864 |
+
self.builder.end_statement(node)
|
| 865 |
+
|
| 866 |
+
def visit_For(self, node):
|
| 867 |
+
self.builder.begin_statement(node)
|
| 868 |
+
self._enter_lexical_scope(node)
|
| 869 |
+
|
| 870 |
+
self.builder.enter_section(node)
|
| 871 |
+
|
| 872 |
+
# Note: Strictly speaking, this should be node.target + node.iter.
|
| 873 |
+
# However, the activity analysis accounts for this inconsistency,
|
| 874 |
+
# so dataflow analysis produces the correct values.
|
| 875 |
+
self.generic_visit(node.iter)
|
| 876 |
+
self.builder.enter_loop_section(node, node.iter)
|
| 877 |
+
# Also include the "extra loop test" annotation, to capture things like the
|
| 878 |
+
# control variable for return and break in for loops.
|
| 879 |
+
if anno.hasanno(node, anno.Basic.EXTRA_LOOP_TEST):
|
| 880 |
+
self._process_basic_statement(
|
| 881 |
+
anno.getanno(node, anno.Basic.EXTRA_LOOP_TEST))
|
| 882 |
+
for stmt in node.body:
|
| 883 |
+
self.visit(stmt)
|
| 884 |
+
self.builder.exit_loop_section(node)
|
| 885 |
+
|
| 886 |
+
# Note: although the orelse is technically part of the loop node,
|
| 887 |
+
# they don't count as loop bodies. For example, a break in the loop's
|
| 888 |
+
# orelse will affect the parent loop, not the current one.
|
| 889 |
+
self._exit_lexical_scope(node)
|
| 890 |
+
|
| 891 |
+
for stmt in node.orelse:
|
| 892 |
+
self.visit(stmt)
|
| 893 |
+
|
| 894 |
+
self.builder.exit_section(node)
|
| 895 |
+
self.builder.end_statement(node)
|
| 896 |
+
|
| 897 |
+
def visit_Break(self, node):
|
| 898 |
+
self._process_exit_statement(node, (
|
| 899 |
+
gast.While,
|
| 900 |
+
gast.For,
|
| 901 |
+
))
|
| 902 |
+
|
| 903 |
+
def visit_Continue(self, node):
|
| 904 |
+
self._process_continue_statement(node, (
|
| 905 |
+
gast.While,
|
| 906 |
+
gast.For,
|
| 907 |
+
))
|
| 908 |
+
|
| 909 |
+
def visit_ExceptHandler(self, node):
|
| 910 |
+
self.builder.begin_statement(node)
|
| 911 |
+
self.builder.enter_except_section(node)
|
| 912 |
+
|
| 913 |
+
if node.type is not None:
|
| 914 |
+
self.visit(node.type)
|
| 915 |
+
if node.name is not None:
|
| 916 |
+
self.visit(node.name)
|
| 917 |
+
|
| 918 |
+
for stmt in node.body:
|
| 919 |
+
self.visit(stmt)
|
| 920 |
+
|
| 921 |
+
self.builder.end_statement(node)
|
| 922 |
+
|
| 923 |
+
def visit_Try(self, node):
|
| 924 |
+
self.builder.begin_statement(node)
|
| 925 |
+
self._enter_lexical_scope(node)
|
| 926 |
+
|
| 927 |
+
# Note: the current simplification is that the try block fully executes
|
| 928 |
+
# regardless of whether an exception triggers or not. This is consistent
|
| 929 |
+
# with blocks free of try/except, which also don't account for the
|
| 930 |
+
# possibility of an exception being raised mid-block.
|
| 931 |
+
|
| 932 |
+
for stmt in node.body:
|
| 933 |
+
self.visit(stmt)
|
| 934 |
+
# The orelse is an optional continuation of the body.
|
| 935 |
+
if node.orelse:
|
| 936 |
+
block_representative = node.orelse[0]
|
| 937 |
+
self.builder.enter_cond_section(block_representative)
|
| 938 |
+
self.builder.new_cond_branch(block_representative)
|
| 939 |
+
for stmt in node.orelse:
|
| 940 |
+
self.visit(stmt)
|
| 941 |
+
self.builder.new_cond_branch(block_representative)
|
| 942 |
+
self.builder.exit_cond_section(block_representative)
|
| 943 |
+
|
| 944 |
+
self._exit_lexical_scope(node)
|
| 945 |
+
|
| 946 |
+
if node.handlers:
|
| 947 |
+
# Using node would be inconsistent. Using the first handler node is also
|
| 948 |
+
# inconsistent, but less so.
|
| 949 |
+
block_representative = node.handlers[0]
|
| 950 |
+
self.builder.enter_cond_section(block_representative)
|
| 951 |
+
for block in node.handlers:
|
| 952 |
+
self.builder.new_cond_branch(block_representative)
|
| 953 |
+
self.visit(block)
|
| 954 |
+
self.builder.new_cond_branch(block_representative)
|
| 955 |
+
self.builder.exit_cond_section(block_representative)
|
| 956 |
+
|
| 957 |
+
if node.finalbody:
|
| 958 |
+
self.builder.enter_finally_section(node)
|
| 959 |
+
for stmt in node.finalbody:
|
| 960 |
+
self.visit(stmt)
|
| 961 |
+
self.builder.exit_finally_section(node)
|
| 962 |
+
|
| 963 |
+
self.builder.end_statement(node)
|
| 964 |
+
|
| 965 |
+
def visit_With(self, node):
|
| 966 |
+
# TODO(mdan): Mark the context manager's exit call as exit guard.
|
| 967 |
+
for item in node.items:
|
| 968 |
+
self._process_basic_statement(item)
|
| 969 |
+
for stmt in node.body:
|
| 970 |
+
self.visit(stmt)
|
| 971 |
+
|
| 972 |
+
|
| 973 |
+
def build(node):
|
| 974 |
+
visitor = AstToCfg()
|
| 975 |
+
visitor.visit(node)
|
| 976 |
+
return visitor.cfgs
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/error_utils.py
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Code transformation exceptions."""
|
| 16 |
+
|
| 17 |
+
import collections
|
| 18 |
+
|
| 19 |
+
from tensorflow.python.autograph.pyct import origin_info
|
| 20 |
+
from tensorflow.python.util import traceback_utils
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
class FrameInfo(
|
| 24 |
+
collections.namedtuple('FrameInfo',
|
| 25 |
+
('filename', 'lineno', 'function_name', 'code',
|
| 26 |
+
'is_converted', 'is_allowlisted'))):
|
| 27 |
+
|
| 28 |
+
__slots__ = ()
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def _stack_trace_inside_mapped_code(tb, source_map, converter_filename):
|
| 32 |
+
"""Summarizes inner traceback frames up to the call to a given function.
|
| 33 |
+
|
| 34 |
+
This functions locates the innermost (i.e. most recent) frame that corresponds
|
| 35 |
+
to code that can be mapped by source_map originated from, and returns a
|
| 36 |
+
translated stack trace ending at that frame. If no such frame is found, the
|
| 37 |
+
entire stack trace is summarized.
|
| 38 |
+
|
| 39 |
+
For example, the following code:
|
| 40 |
+
|
| 41 |
+
def f():
|
| 42 |
+
for i in tf.range(1):
|
| 43 |
+
z = y + i # z only defined here
|
| 44 |
+
|
| 45 |
+
Would generate this traceback:
|
| 46 |
+
|
| 47 |
+
<converted code>
|
| 48 |
+
ag__.for_stmt(...)
|
| 49 |
+
<for_stmt>
|
| 50 |
+
return _known_len_tf_for_stmt(iter_, extra_test, body, init_state)
|
| 51 |
+
<_known_len_tf_for_stmt>
|
| 52 |
+
_disallow_undefs_into_loop(*init_state)
|
| 53 |
+
<_disallow_undefs_into_loop>
|
| 54 |
+
raise ...
|
| 55 |
+
|
| 56 |
+
Which is then processed into:
|
| 57 |
+
|
| 58 |
+
<f>
|
| 59 |
+
for i in tf.range(1):
|
| 60 |
+
<for_stmt>
|
| 61 |
+
return _known_len_tf_for_stmt(iter_, extra_test, body, init_state)
|
| 62 |
+
<_known_len_tf_for_stmt>
|
| 63 |
+
_disallow_undefs_into_loop(*init_state)
|
| 64 |
+
<_disallow_undefs_into_loop>
|
| 65 |
+
raise ...
|
| 66 |
+
|
| 67 |
+
Args:
|
| 68 |
+
tb: traceback.FrameSummary, The traceback corresponding to an error.
|
| 69 |
+
Typically, the output of traceback.Summary.extract(capture_locals=True).
|
| 70 |
+
source_map: Dict[LineLocation, OriginInfo], a source map as created by
|
| 71 |
+
origin_info.create_source_map.
|
| 72 |
+
converter_filename: str, the file path of the converted module. Call frames
|
| 73 |
+
corresponding to this module are elided and their preceding frames are
|
| 74 |
+
marked as allowlisted. Note that frames enclosing converted code are
|
| 75 |
+
dropped using a different mechanism.
|
| 76 |
+
|
| 77 |
+
Returns:
|
| 78 |
+
List[FrameInfo]
|
| 79 |
+
"""
|
| 80 |
+
result_frames = []
|
| 81 |
+
for filename, line_number, function_name, text in reversed(tb):
|
| 82 |
+
|
| 83 |
+
loc = origin_info.LineLocation(filename=filename, lineno=line_number)
|
| 84 |
+
if loc in source_map:
|
| 85 |
+
origin = source_map[loc]
|
| 86 |
+
fi = FrameInfo(
|
| 87 |
+
filename=origin.loc.filename,
|
| 88 |
+
lineno=origin.loc.lineno,
|
| 89 |
+
function_name=origin.function_name,
|
| 90 |
+
code=origin.source_code_line,
|
| 91 |
+
is_converted=True,
|
| 92 |
+
is_allowlisted=False)
|
| 93 |
+
result_frames.append(fi)
|
| 94 |
+
break
|
| 95 |
+
|
| 96 |
+
if filename == converter_filename:
|
| 97 |
+
if result_frames:
|
| 98 |
+
prev = result_frames[-1]
|
| 99 |
+
assert not prev.is_converted # See the if above.
|
| 100 |
+
fi = FrameInfo(
|
| 101 |
+
filename=prev.filename,
|
| 102 |
+
lineno=prev.lineno,
|
| 103 |
+
function_name=prev.function_name,
|
| 104 |
+
code=prev.code,
|
| 105 |
+
is_converted=False,
|
| 106 |
+
is_allowlisted=True)
|
| 107 |
+
result_frames[-1] = fi
|
| 108 |
+
continue
|
| 109 |
+
|
| 110 |
+
fi = FrameInfo(
|
| 111 |
+
filename=filename,
|
| 112 |
+
lineno=line_number,
|
| 113 |
+
function_name=function_name,
|
| 114 |
+
code=text,
|
| 115 |
+
is_converted=False,
|
| 116 |
+
is_allowlisted=False)
|
| 117 |
+
result_frames.append(fi)
|
| 118 |
+
|
| 119 |
+
return tuple(result_frames)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
KNOWN_STRING_CONSTRUCTOR_ERRORS = (
|
| 123 |
+
AssertionError,
|
| 124 |
+
AttributeError,
|
| 125 |
+
NameError,
|
| 126 |
+
NotImplementedError,
|
| 127 |
+
RuntimeError,
|
| 128 |
+
StopIteration,
|
| 129 |
+
TypeError,
|
| 130 |
+
UnboundLocalError,
|
| 131 |
+
ValueError,
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
# KeyError escapes newlines in strings. We create a special subclass
|
| 136 |
+
# that doesn't do that. Overriding the name for display purposes; hopefully
|
| 137 |
+
# that won't create too many surprises.
|
| 138 |
+
class MultilineMessageKeyError(KeyError):
|
| 139 |
+
|
| 140 |
+
def __init__(self, message, original_key):
|
| 141 |
+
super(MultilineMessageKeyError, self).__init__(original_key)
|
| 142 |
+
self.__message = message
|
| 143 |
+
|
| 144 |
+
def __str__(self):
|
| 145 |
+
return self.__message
|
| 146 |
+
|
| 147 |
+
MultilineMessageKeyError.__name__ = KeyError.__name__
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
class ErrorMetadataBase(object):
|
| 151 |
+
"""Container objects attached to exceptions raised in user code.
|
| 152 |
+
|
| 153 |
+
This metadata allows re-raising exceptions that occur in generated code, with
|
| 154 |
+
a custom error message that includes a stack trace relative to user-readable
|
| 155 |
+
code from which the generated code originated.
|
| 156 |
+
"""
|
| 157 |
+
|
| 158 |
+
__slots__ = ('translated_stack', 'cause_message')
|
| 159 |
+
|
| 160 |
+
def __init__(self, callsite_tb, cause_metadata, cause_message, source_map,
|
| 161 |
+
converter_filename):
|
| 162 |
+
translated_stack = _stack_trace_inside_mapped_code(
|
| 163 |
+
callsite_tb, source_map, converter_filename)
|
| 164 |
+
|
| 165 |
+
if cause_metadata is None:
|
| 166 |
+
self.translated_stack = translated_stack
|
| 167 |
+
self.cause_message = cause_message
|
| 168 |
+
else:
|
| 169 |
+
# Daisy chain the translated stacks.
|
| 170 |
+
self.translated_stack = (
|
| 171 |
+
cause_metadata.translated_stack + (translated_stack[-1],))
|
| 172 |
+
self.cause_message = cause_metadata.cause_message
|
| 173 |
+
|
| 174 |
+
def get_message(self):
|
| 175 |
+
"""Returns the message for the underlying exception."""
|
| 176 |
+
lines = []
|
| 177 |
+
|
| 178 |
+
lines.append('in user code:')
|
| 179 |
+
lines.append('')
|
| 180 |
+
|
| 181 |
+
for frame_info in reversed(self.translated_stack):
|
| 182 |
+
if (traceback_utils.is_traceback_filtering_enabled() and
|
| 183 |
+
not traceback_utils.include_frame(frame_info.filename)):
|
| 184 |
+
continue
|
| 185 |
+
|
| 186 |
+
# Same format with Python traceback.
|
| 187 |
+
formatted_line = (f' File "{frame_info.filename}", line '
|
| 188 |
+
f'{frame_info.lineno}, in {frame_info.function_name}')
|
| 189 |
+
if frame_info.is_converted:
|
| 190 |
+
formatted_line += ' *'
|
| 191 |
+
elif frame_info.is_allowlisted:
|
| 192 |
+
formatted_line += ' **'
|
| 193 |
+
lines.append(formatted_line)
|
| 194 |
+
|
| 195 |
+
if frame_info.code is None:
|
| 196 |
+
code_snippet = '<source unavailable>'
|
| 197 |
+
else:
|
| 198 |
+
code_snippet = frame_info.code.strip()
|
| 199 |
+
lines.append(' {}'.format(code_snippet))
|
| 200 |
+
|
| 201 |
+
lines.append('')
|
| 202 |
+
|
| 203 |
+
message_lines = self.cause_message.split('\n')
|
| 204 |
+
for i in range(len(message_lines)):
|
| 205 |
+
message_lines[i] = ' ' + message_lines[i]
|
| 206 |
+
lines.extend(message_lines)
|
| 207 |
+
|
| 208 |
+
lines.append('')
|
| 209 |
+
|
| 210 |
+
return '\n'.join(lines)
|
| 211 |
+
|
| 212 |
+
def create_exception(self, source_error):
|
| 213 |
+
"""Creates exception from source_error."""
|
| 214 |
+
preferred_type = type(source_error)
|
| 215 |
+
to_ret = None
|
| 216 |
+
if preferred_type.__init__ is Exception.__init__:
|
| 217 |
+
to_ret = preferred_type(self.get_message())
|
| 218 |
+
if preferred_type in KNOWN_STRING_CONSTRUCTOR_ERRORS:
|
| 219 |
+
to_ret = preferred_type(self.get_message())
|
| 220 |
+
elif preferred_type is KeyError:
|
| 221 |
+
to_ret = MultilineMessageKeyError(self.get_message(), self.cause_message)
|
| 222 |
+
|
| 223 |
+
if to_ret is not None:
|
| 224 |
+
return to_ret.with_traceback(source_error.__traceback__)
|
| 225 |
+
|
| 226 |
+
def to_exception(self, source_error):
|
| 227 |
+
exc = self.create_exception(source_error)
|
| 228 |
+
exc.__suppress_context__ = True
|
| 229 |
+
exc.ag_error_metadata = self
|
| 230 |
+
return exc
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/errors.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Code transformation exceptions."""
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class PyCTError(Exception):
|
| 19 |
+
"""Base class for all exceptions."""
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class UnsupportedLanguageElementError(PyCTError, NotImplementedError):
|
| 23 |
+
"""Raised for code patterns that AutoGraph does not support."""
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class InaccessibleSourceCodeError(PyCTError, ValueError):
|
| 27 |
+
"""Raised when inspect can not access source code."""
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/gast_util.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Gast compatibility library. Supports 0.2.2 and 0.3.2."""
|
| 16 |
+
# TODO(mdan): Remove this file once it's safe to break compatibility.
|
| 17 |
+
|
| 18 |
+
import functools
|
| 19 |
+
|
| 20 |
+
import gast
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
GAST2 = hasattr(gast, 'Str')
|
| 24 |
+
GAST3 = not GAST2
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def _is_constant_gast_2(node):
|
| 28 |
+
return isinstance(node, (gast.Num, gast.Str, gast.Bytes, gast.Ellipsis,
|
| 29 |
+
gast.NameConstant))
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def _is_constant_gast_3(node):
|
| 33 |
+
return isinstance(node, gast.Constant)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def is_literal(node):
|
| 37 |
+
"""Tests whether node represents a Python literal."""
|
| 38 |
+
# Normal literals, True/False/None/Etc. in Python3
|
| 39 |
+
if is_constant(node):
|
| 40 |
+
return True
|
| 41 |
+
|
| 42 |
+
# True/False/None/Etc. in Python2
|
| 43 |
+
if isinstance(node, gast.Name) and node.id in ['True', 'False', 'None']:
|
| 44 |
+
return True
|
| 45 |
+
|
| 46 |
+
return False
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def _is_ellipsis_gast_2(node):
|
| 50 |
+
return isinstance(node, gast.Ellipsis)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def _is_ellipsis_gast_3(node):
|
| 54 |
+
return isinstance(node, gast.Constant) and node.value == Ellipsis
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
if GAST2:
|
| 58 |
+
is_constant = _is_constant_gast_2
|
| 59 |
+
is_ellipsis = _is_ellipsis_gast_2
|
| 60 |
+
|
| 61 |
+
Module = gast.Module
|
| 62 |
+
Name = gast.Name
|
| 63 |
+
Str = gast.Str
|
| 64 |
+
|
| 65 |
+
elif GAST3:
|
| 66 |
+
is_constant = _is_constant_gast_3
|
| 67 |
+
is_ellipsis = _is_ellipsis_gast_3
|
| 68 |
+
|
| 69 |
+
Module = functools.partial(gast.Module, type_ignores=None) # pylint:disable=invalid-name
|
| 70 |
+
Name = functools.partial(gast.Name, type_comment=None) # pylint:disable=invalid-name
|
| 71 |
+
Str = functools.partial(gast.Constant, kind=None) # pylint:disable=invalid-name
|
| 72 |
+
|
| 73 |
+
else:
|
| 74 |
+
assert False
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/inspect_utils.py
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Live entity inspection utilities.
|
| 16 |
+
|
| 17 |
+
This module contains whatever inspect doesn't offer out of the box.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
import builtins
|
| 21 |
+
import inspect
|
| 22 |
+
import itertools
|
| 23 |
+
import linecache
|
| 24 |
+
import sys
|
| 25 |
+
import threading
|
| 26 |
+
import types
|
| 27 |
+
|
| 28 |
+
from tensorflow.python.util import tf_inspect
|
| 29 |
+
|
| 30 |
+
# This lock seems to help avoid linecache concurrency errors.
|
| 31 |
+
_linecache_lock = threading.Lock()
|
| 32 |
+
|
| 33 |
+
# Cache all the builtin elements in a frozen set for faster lookup.
|
| 34 |
+
_BUILTIN_FUNCTION_IDS = frozenset(id(v) for v in builtins.__dict__.values())
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def islambda(f):
|
| 38 |
+
if not tf_inspect.isfunction(f):
|
| 39 |
+
return False
|
| 40 |
+
# TODO(mdan): Look into checking the only the code object.
|
| 41 |
+
if not (hasattr(f, '__name__') and hasattr(f, '__code__')):
|
| 42 |
+
return False
|
| 43 |
+
# Some wrappers can rename the function, but changing the name of the
|
| 44 |
+
# code object is harder.
|
| 45 |
+
return ((f.__name__ == '<lambda>') or (f.__code__.co_name == '<lambda>'))
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def isnamedtuple(f):
|
| 49 |
+
"""Returns True if the argument is a namedtuple-like."""
|
| 50 |
+
if not (tf_inspect.isclass(f) and issubclass(f, tuple)):
|
| 51 |
+
return False
|
| 52 |
+
if not hasattr(f, '_fields'):
|
| 53 |
+
return False
|
| 54 |
+
fields = getattr(f, '_fields')
|
| 55 |
+
if not isinstance(fields, tuple):
|
| 56 |
+
return False
|
| 57 |
+
if not all(isinstance(f, str) for f in fields):
|
| 58 |
+
return False
|
| 59 |
+
return True
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def isbuiltin(f):
|
| 63 |
+
"""Returns True if the argument is a built-in function."""
|
| 64 |
+
if id(f) in _BUILTIN_FUNCTION_IDS:
|
| 65 |
+
return True
|
| 66 |
+
elif isinstance(f, types.BuiltinFunctionType):
|
| 67 |
+
return True
|
| 68 |
+
elif inspect.isbuiltin(f):
|
| 69 |
+
return True
|
| 70 |
+
elif f is eval:
|
| 71 |
+
return True
|
| 72 |
+
else:
|
| 73 |
+
return False
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def isconstructor(cls):
|
| 77 |
+
"""Returns True if the argument is an object constructor.
|
| 78 |
+
|
| 79 |
+
In general, any object of type class is a constructor, with the exception
|
| 80 |
+
of classes created using a callable metaclass.
|
| 81 |
+
See below for why a callable metaclass is not a trivial combination:
|
| 82 |
+
https://docs.python.org/2.7/reference/datamodel.html#customizing-class-creation
|
| 83 |
+
|
| 84 |
+
Args:
|
| 85 |
+
cls: Any
|
| 86 |
+
|
| 87 |
+
Returns:
|
| 88 |
+
Bool
|
| 89 |
+
"""
|
| 90 |
+
return (inspect.isclass(cls) and
|
| 91 |
+
not (issubclass(cls.__class__, type) and
|
| 92 |
+
hasattr(cls.__class__, '__call__') and
|
| 93 |
+
cls.__class__.__call__ is not type.__call__))
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def _fix_linecache_record(obj):
|
| 97 |
+
"""Fixes potential corruption of linecache in the presence of functools.wraps.
|
| 98 |
+
|
| 99 |
+
functools.wraps modifies the target object's __module__ field, which seems
|
| 100 |
+
to confuse linecache in special instances, for example when the source is
|
| 101 |
+
loaded from a .par file (see https://google.github.io/subpar/subpar.html).
|
| 102 |
+
|
| 103 |
+
This function simply triggers a call to linecache.updatecache when a mismatch
|
| 104 |
+
was detected between the object's __module__ property and the object's source
|
| 105 |
+
file.
|
| 106 |
+
|
| 107 |
+
Args:
|
| 108 |
+
obj: Any
|
| 109 |
+
"""
|
| 110 |
+
if hasattr(obj, '__module__'):
|
| 111 |
+
obj_file = inspect.getfile(obj)
|
| 112 |
+
obj_module = obj.__module__
|
| 113 |
+
|
| 114 |
+
# A snapshot of the loaded modules helps avoid "dict changed size during
|
| 115 |
+
# iteration" errors.
|
| 116 |
+
loaded_modules = tuple(sys.modules.values())
|
| 117 |
+
for m in loaded_modules:
|
| 118 |
+
if hasattr(m, '__file__') and m.__file__ == obj_file:
|
| 119 |
+
if obj_module is not m:
|
| 120 |
+
linecache.updatecache(obj_file, m.__dict__)
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def getimmediatesource(obj):
|
| 124 |
+
"""A variant of inspect.getsource that ignores the __wrapped__ property."""
|
| 125 |
+
with _linecache_lock:
|
| 126 |
+
_fix_linecache_record(obj)
|
| 127 |
+
lines, lnum = inspect.findsource(obj)
|
| 128 |
+
return ''.join(inspect.getblock(lines[lnum:]))
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def getnamespace(f):
|
| 132 |
+
"""Returns the complete namespace of a function.
|
| 133 |
+
|
| 134 |
+
Namespace is defined here as the mapping of all non-local variables to values.
|
| 135 |
+
This includes the globals and the closure variables. Note that this captures
|
| 136 |
+
the entire globals collection of the function, and may contain extra symbols
|
| 137 |
+
that it does not actually use.
|
| 138 |
+
|
| 139 |
+
Args:
|
| 140 |
+
f: User defined function.
|
| 141 |
+
|
| 142 |
+
Returns:
|
| 143 |
+
A dict mapping symbol names to values.
|
| 144 |
+
"""
|
| 145 |
+
namespace = dict(f.__globals__)
|
| 146 |
+
closure = f.__closure__
|
| 147 |
+
freevars = f.__code__.co_freevars
|
| 148 |
+
if freevars and closure:
|
| 149 |
+
for name, cell in zip(freevars, closure):
|
| 150 |
+
try:
|
| 151 |
+
namespace[name] = cell.cell_contents
|
| 152 |
+
except ValueError:
|
| 153 |
+
# Cell contains undefined variable, omit it from the namespace.
|
| 154 |
+
pass
|
| 155 |
+
return namespace
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def getqualifiedname(namespace, object_, max_depth=5, visited=None):
|
| 159 |
+
"""Returns the name by which a value can be referred to in a given namespace.
|
| 160 |
+
|
| 161 |
+
If the object defines a parent module, the function attempts to use it to
|
| 162 |
+
locate the object.
|
| 163 |
+
|
| 164 |
+
This function will recurse inside modules, but it will not search objects for
|
| 165 |
+
attributes. The recursion depth is controlled by max_depth.
|
| 166 |
+
|
| 167 |
+
Args:
|
| 168 |
+
namespace: Dict[str, Any], the namespace to search into.
|
| 169 |
+
object_: Any, the value to search.
|
| 170 |
+
max_depth: Optional[int], a limit to the recursion depth when searching
|
| 171 |
+
inside modules.
|
| 172 |
+
visited: Optional[Set[int]], ID of modules to avoid visiting.
|
| 173 |
+
Returns: Union[str, None], the fully-qualified name that resolves to the value
|
| 174 |
+
o, or None if it couldn't be found.
|
| 175 |
+
"""
|
| 176 |
+
if visited is None:
|
| 177 |
+
visited = set()
|
| 178 |
+
|
| 179 |
+
# Copy the dict to avoid "changed size error" during concurrent invocations.
|
| 180 |
+
# TODO(mdan): This is on the hot path. Can we avoid the copy?
|
| 181 |
+
namespace = dict(namespace)
|
| 182 |
+
|
| 183 |
+
for name in namespace:
|
| 184 |
+
# The value may be referenced by more than one symbol, case in which
|
| 185 |
+
# any symbol will be fine. If the program contains symbol aliases that
|
| 186 |
+
# change over time, this may capture a symbol that will later point to
|
| 187 |
+
# something else.
|
| 188 |
+
# TODO(mdan): Prefer the symbol that matches the value type name.
|
| 189 |
+
if object_ is namespace[name]:
|
| 190 |
+
return name
|
| 191 |
+
|
| 192 |
+
# If an object is not found, try to search its parent modules.
|
| 193 |
+
parent = tf_inspect.getmodule(object_)
|
| 194 |
+
if (parent is not None and parent is not object_ and parent is not namespace):
|
| 195 |
+
# No limit to recursion depth because of the guard above.
|
| 196 |
+
parent_name = getqualifiedname(
|
| 197 |
+
namespace, parent, max_depth=0, visited=visited)
|
| 198 |
+
if parent_name is not None:
|
| 199 |
+
name_in_parent = getqualifiedname(
|
| 200 |
+
parent.__dict__, object_, max_depth=0, visited=visited)
|
| 201 |
+
assert name_in_parent is not None, (
|
| 202 |
+
'An object should always be found in its owner module')
|
| 203 |
+
return '{}.{}'.format(parent_name, name_in_parent)
|
| 204 |
+
|
| 205 |
+
if max_depth:
|
| 206 |
+
# Iterating over a copy prevents "changed size due to iteration" errors.
|
| 207 |
+
# It's unclear why those occur - suspecting new modules may load during
|
| 208 |
+
# iteration.
|
| 209 |
+
for name in namespace.keys():
|
| 210 |
+
value = namespace[name]
|
| 211 |
+
if tf_inspect.ismodule(value) and id(value) not in visited:
|
| 212 |
+
visited.add(id(value))
|
| 213 |
+
name_in_module = getqualifiedname(value.__dict__, object_,
|
| 214 |
+
max_depth - 1, visited)
|
| 215 |
+
if name_in_module is not None:
|
| 216 |
+
return '{}.{}'.format(name, name_in_module)
|
| 217 |
+
return None
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def getdefiningclass(m, owner_class):
|
| 221 |
+
"""Resolves the class (e.g. one of the superclasses) that defined a method."""
|
| 222 |
+
method_name = m.__name__
|
| 223 |
+
for super_class in inspect.getmro(owner_class):
|
| 224 |
+
if ((hasattr(super_class, '__dict__') and
|
| 225 |
+
method_name in super_class.__dict__) or
|
| 226 |
+
(hasattr(super_class, '__slots__') and
|
| 227 |
+
method_name in super_class.__slots__)):
|
| 228 |
+
return super_class
|
| 229 |
+
return owner_class
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
def getmethodclass(m):
|
| 233 |
+
"""Resolves a function's owner, e.g.
|
| 234 |
+
|
| 235 |
+
a method's class.
|
| 236 |
+
|
| 237 |
+
Note that this returns the object that the function was retrieved from, not
|
| 238 |
+
necessarily the class where it was defined.
|
| 239 |
+
|
| 240 |
+
This function relies on Python stack frame support in the interpreter, and
|
| 241 |
+
has the same limitations that inspect.currentframe.
|
| 242 |
+
|
| 243 |
+
Limitations. This function will only work correctly if the owned class is
|
| 244 |
+
visible in the caller's global or local variables.
|
| 245 |
+
|
| 246 |
+
Args:
|
| 247 |
+
m: A user defined function
|
| 248 |
+
|
| 249 |
+
Returns:
|
| 250 |
+
The class that this function was retrieved from, or None if the function
|
| 251 |
+
is not an object or class method, or the class that owns the object or
|
| 252 |
+
method is not visible to m.
|
| 253 |
+
|
| 254 |
+
Raises:
|
| 255 |
+
ValueError: if the class could not be resolved for any unexpected reason.
|
| 256 |
+
"""
|
| 257 |
+
|
| 258 |
+
# Callable objects: return their own class.
|
| 259 |
+
if (not hasattr(m, '__name__') and hasattr(m, '__class__') and
|
| 260 |
+
hasattr(m, '__call__')):
|
| 261 |
+
if isinstance(m.__class__, type):
|
| 262 |
+
return m.__class__
|
| 263 |
+
|
| 264 |
+
# Instance and class: return the class of "self".
|
| 265 |
+
m_self = getattr(m, '__self__', None)
|
| 266 |
+
if m_self is not None:
|
| 267 |
+
if inspect.isclass(m_self):
|
| 268 |
+
return m_self
|
| 269 |
+
return m_self.__class__
|
| 270 |
+
|
| 271 |
+
# Class, static and unbound methods: search all defined classes in any
|
| 272 |
+
# namespace. This is inefficient but more robust a method.
|
| 273 |
+
owners = []
|
| 274 |
+
caller_frame = tf_inspect.currentframe().f_back
|
| 275 |
+
try:
|
| 276 |
+
# TODO(mdan): This doesn't consider cell variables.
|
| 277 |
+
# TODO(mdan): This won't work if the owner is hidden inside a container.
|
| 278 |
+
# Cell variables may be pulled using co_freevars and the closure.
|
| 279 |
+
for v in itertools.chain(caller_frame.f_locals.values(),
|
| 280 |
+
caller_frame.f_globals.values()):
|
| 281 |
+
if hasattr(v, m.__name__):
|
| 282 |
+
candidate = getattr(v, m.__name__)
|
| 283 |
+
# Py2 methods may be bound or unbound, extract im_func to get the
|
| 284 |
+
# underlying function.
|
| 285 |
+
if hasattr(candidate, 'im_func'):
|
| 286 |
+
candidate = candidate.im_func
|
| 287 |
+
if hasattr(m, 'im_func'):
|
| 288 |
+
m = m.im_func
|
| 289 |
+
if candidate is m:
|
| 290 |
+
owners.append(v)
|
| 291 |
+
finally:
|
| 292 |
+
del caller_frame
|
| 293 |
+
|
| 294 |
+
if owners:
|
| 295 |
+
if len(owners) == 1:
|
| 296 |
+
return owners[0]
|
| 297 |
+
|
| 298 |
+
# If multiple owners are found, and are not subclasses, raise an error.
|
| 299 |
+
owner_types = tuple(o if tf_inspect.isclass(o) else type(o) for o in owners)
|
| 300 |
+
for o in owner_types:
|
| 301 |
+
if tf_inspect.isclass(o) and issubclass(o, tuple(owner_types)):
|
| 302 |
+
return o
|
| 303 |
+
raise ValueError('Found too many owners of %s: %s' % (m, owners))
|
| 304 |
+
|
| 305 |
+
return None
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
def getfutureimports(entity):
|
| 309 |
+
"""Detects what future imports are necessary to safely execute entity source.
|
| 310 |
+
|
| 311 |
+
Args:
|
| 312 |
+
entity: Any object
|
| 313 |
+
|
| 314 |
+
Returns:
|
| 315 |
+
A tuple of future strings
|
| 316 |
+
"""
|
| 317 |
+
if not (tf_inspect.isfunction(entity) or tf_inspect.ismethod(entity)):
|
| 318 |
+
return tuple()
|
| 319 |
+
return tuple(
|
| 320 |
+
sorted(name for name, value in entity.__globals__.items()
|
| 321 |
+
if getattr(value, '__module__', None) == '__future__'))
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/loader.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Converting AST to code and Python entities.
|
| 16 |
+
|
| 17 |
+
Adapted from Tangent.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
import atexit
|
| 21 |
+
import errno
|
| 22 |
+
import importlib
|
| 23 |
+
import os
|
| 24 |
+
import sys
|
| 25 |
+
import tempfile
|
| 26 |
+
|
| 27 |
+
from tensorflow.python.autograph.pyct import origin_info
|
| 28 |
+
from tensorflow.python.autograph.pyct import parser
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def _remove_file(file_name):
|
| 32 |
+
"""Remove a file, if it exists."""
|
| 33 |
+
try:
|
| 34 |
+
os.remove(file_name)
|
| 35 |
+
except OSError as e:
|
| 36 |
+
if e.errno == errno.ENOENT:
|
| 37 |
+
# The file disappeared. Ignore this. Temporary files might get
|
| 38 |
+
# cleaned up, especially if they reside in /tmp.
|
| 39 |
+
pass
|
| 40 |
+
else:
|
| 41 |
+
raise
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def load_source(source, delete_on_exit):
|
| 45 |
+
"""Loads the given source code as a Python module."""
|
| 46 |
+
with tempfile.NamedTemporaryFile(
|
| 47 |
+
mode='w',
|
| 48 |
+
suffix='.py',
|
| 49 |
+
prefix='__autograph_generated_file',
|
| 50 |
+
delete=False,
|
| 51 |
+
encoding='utf-8') as f:
|
| 52 |
+
module_name = os.path.basename(f.name[:-3])
|
| 53 |
+
file_name = f.name
|
| 54 |
+
f.write(source)
|
| 55 |
+
|
| 56 |
+
if delete_on_exit:
|
| 57 |
+
atexit.register(lambda: _remove_file(file_name))
|
| 58 |
+
|
| 59 |
+
spec = importlib.util.spec_from_file_location(module_name, file_name)
|
| 60 |
+
module = importlib.util.module_from_spec(spec)
|
| 61 |
+
spec.loader.exec_module(module)
|
| 62 |
+
# TODO(mdan): Use our own garbage-collected cache instead of sys.modules.
|
| 63 |
+
sys.modules[module_name] = module
|
| 64 |
+
return module, file_name
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def load_ast(nodes,
|
| 68 |
+
indentation=' ',
|
| 69 |
+
include_source_map=False,
|
| 70 |
+
delete_on_exit=True):
|
| 71 |
+
"""Loads the given AST as a Python module.
|
| 72 |
+
|
| 73 |
+
Compiling the AST code this way ensures that the source code is readable by
|
| 74 |
+
e.g. `pdb` or `inspect`.
|
| 75 |
+
|
| 76 |
+
Args:
|
| 77 |
+
nodes: Union[ast.AST, Iterable[ast.AST]], the code to compile, as an AST
|
| 78 |
+
object.
|
| 79 |
+
indentation: Text, the string to use for indentation.
|
| 80 |
+
include_source_map: bool, whether return a source map.
|
| 81 |
+
delete_on_exit: bool, whether to delete the temporary file used for
|
| 82 |
+
compilation on exit.
|
| 83 |
+
|
| 84 |
+
Returns:
|
| 85 |
+
Tuple[module, Text, Dict[LineLocation, OriginInfo]], containing:
|
| 86 |
+
the module containing the unparsed nodes, the source code corresponding to
|
| 87 |
+
nodes, and the source map. Is include_source_map is False, the source map
|
| 88 |
+
will be None.
|
| 89 |
+
"""
|
| 90 |
+
if not isinstance(nodes, (list, tuple)):
|
| 91 |
+
nodes = (nodes,)
|
| 92 |
+
|
| 93 |
+
source = parser.unparse(nodes, indentation=indentation)
|
| 94 |
+
module, _ = load_source(source, delete_on_exit)
|
| 95 |
+
|
| 96 |
+
if include_source_map:
|
| 97 |
+
source_map = origin_info.create_source_map(nodes, source, module.__file__)
|
| 98 |
+
else:
|
| 99 |
+
source_map = None
|
| 100 |
+
|
| 101 |
+
# TODO(mdan): Return a structured object.
|
| 102 |
+
return module, source, source_map
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/naming.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Symbol naming utilities."""
|
| 16 |
+
|
| 17 |
+
from tensorflow.python.autograph.pyct import qual_names
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class Namer(object):
|
| 21 |
+
"""Symbol name generator."""
|
| 22 |
+
|
| 23 |
+
def __init__(self, global_namespace):
|
| 24 |
+
self.global_namespace = global_namespace
|
| 25 |
+
self.generated_names = set()
|
| 26 |
+
|
| 27 |
+
def new_symbol(self, name_root, reserved_locals):
|
| 28 |
+
"""See control_flow.SymbolNamer.new_symbol."""
|
| 29 |
+
# reserved_locals may contain QNs.
|
| 30 |
+
all_reserved_locals = set()
|
| 31 |
+
for s in reserved_locals:
|
| 32 |
+
if isinstance(s, qual_names.QN):
|
| 33 |
+
all_reserved_locals.update(s.qn)
|
| 34 |
+
elif isinstance(s, str):
|
| 35 |
+
all_reserved_locals.add(s)
|
| 36 |
+
else:
|
| 37 |
+
raise ValueError('Unexpected symbol type "%s"' % type(s))
|
| 38 |
+
|
| 39 |
+
pieces = name_root.split('_')
|
| 40 |
+
if pieces[-1].isdigit():
|
| 41 |
+
name_root = '_'.join(pieces[:-1])
|
| 42 |
+
n = int(pieces[-1])
|
| 43 |
+
else:
|
| 44 |
+
n = 0
|
| 45 |
+
new_name = name_root
|
| 46 |
+
|
| 47 |
+
while (new_name in self.global_namespace or
|
| 48 |
+
new_name in all_reserved_locals or new_name in self.generated_names):
|
| 49 |
+
n += 1
|
| 50 |
+
new_name = '%s_%d' % (name_root, n)
|
| 51 |
+
|
| 52 |
+
self.generated_names.add(new_name)
|
| 53 |
+
return new_name
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/origin_info.py
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2018 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Container for origin source code information before AutoGraph compilation."""
|
| 16 |
+
import collections
|
| 17 |
+
import difflib
|
| 18 |
+
import io
|
| 19 |
+
import os
|
| 20 |
+
import tokenize
|
| 21 |
+
|
| 22 |
+
import gast
|
| 23 |
+
|
| 24 |
+
from tensorflow.python.autograph.pyct import anno
|
| 25 |
+
from tensorflow.python.autograph.pyct import ast_util
|
| 26 |
+
from tensorflow.python.autograph.pyct import parser
|
| 27 |
+
from tensorflow.python.autograph.pyct import pretty_printer
|
| 28 |
+
from tensorflow.python.util import tf_inspect
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class LineLocation(
|
| 32 |
+
collections.namedtuple('LineLocation', ('filename', 'lineno'))):
|
| 33 |
+
"""Similar to Location, but without column information.
|
| 34 |
+
|
| 35 |
+
Attributes:
|
| 36 |
+
filename: Text
|
| 37 |
+
lineno: int, 1-based
|
| 38 |
+
"""
|
| 39 |
+
pass
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class Location(
|
| 43 |
+
collections.namedtuple('Location', ('filename', 'lineno', 'col_offset'))):
|
| 44 |
+
"""Encodes code location information.
|
| 45 |
+
|
| 46 |
+
Attributes:
|
| 47 |
+
filename: Text
|
| 48 |
+
lineno: int, 1-based
|
| 49 |
+
col_offset: int
|
| 50 |
+
line_loc: LineLocation
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
@property
|
| 54 |
+
def line_loc(self):
|
| 55 |
+
return LineLocation(self.filename, self.lineno)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
class OriginInfo(
|
| 59 |
+
collections.namedtuple(
|
| 60 |
+
'OriginInfo',
|
| 61 |
+
('loc', 'function_name', 'source_code_line', 'comment'))):
|
| 62 |
+
"""Container for information about the source code before conversion.
|
| 63 |
+
|
| 64 |
+
Attributes:
|
| 65 |
+
loc: Location
|
| 66 |
+
function_name: Optional[Text]
|
| 67 |
+
source_code_line: Text
|
| 68 |
+
comment: Optional[Text]
|
| 69 |
+
"""
|
| 70 |
+
|
| 71 |
+
def as_frame(self):
|
| 72 |
+
"""Returns a 4-tuple consistent with the return of traceback.extract_tb."""
|
| 73 |
+
return (self.loc.filename, self.loc.lineno, self.function_name,
|
| 74 |
+
self.source_code_line)
|
| 75 |
+
|
| 76 |
+
def __repr__(self):
|
| 77 |
+
if self.loc.filename:
|
| 78 |
+
return '{}:{}:{}'.format(
|
| 79 |
+
os.path.split(self.loc.filename)[1], self.loc.lineno,
|
| 80 |
+
self.loc.col_offset)
|
| 81 |
+
return '<no file>:{}:{}'.format(self.loc.lineno, self.loc.col_offset)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
# TODO(mdan): This source map should be a class - easier to refer to.
|
| 85 |
+
def create_source_map(nodes, code, filepath):
|
| 86 |
+
"""Creates a source map between an annotated AST and the code it compiles to.
|
| 87 |
+
|
| 88 |
+
Note: this function assumes nodes nodes, code and filepath correspond to the
|
| 89 |
+
same code.
|
| 90 |
+
|
| 91 |
+
Args:
|
| 92 |
+
nodes: Iterable[ast.AST, ...], one or more AST modes.
|
| 93 |
+
code: Text, the source code in which nodes are found.
|
| 94 |
+
filepath: Text
|
| 95 |
+
|
| 96 |
+
Returns:
|
| 97 |
+
Dict[LineLocation, OriginInfo], mapping locations in code to locations
|
| 98 |
+
indicated by origin annotations in node.
|
| 99 |
+
"""
|
| 100 |
+
reparsed_nodes = parser.parse(code, preamble_len=0, single_node=False)
|
| 101 |
+
for node in reparsed_nodes:
|
| 102 |
+
resolve(node, code, filepath, node.lineno, node.col_offset)
|
| 103 |
+
|
| 104 |
+
source_map = {}
|
| 105 |
+
|
| 106 |
+
try:
|
| 107 |
+
for before, after in ast_util.parallel_walk(nodes, reparsed_nodes):
|
| 108 |
+
# Note: generated code might not be mapped back to its origin.
|
| 109 |
+
# TODO(mdan): Generated code should always be mapped to something.
|
| 110 |
+
origin_info = anno.getanno(before, anno.Basic.ORIGIN, default=None)
|
| 111 |
+
final_info = anno.getanno(after, anno.Basic.ORIGIN, default=None)
|
| 112 |
+
if origin_info is None or final_info is None:
|
| 113 |
+
continue
|
| 114 |
+
|
| 115 |
+
# Note: the keys are by line only, excluding the column offset.
|
| 116 |
+
line_loc = LineLocation(final_info.loc.filename, final_info.loc.lineno)
|
| 117 |
+
|
| 118 |
+
existing_origin = source_map.get(line_loc)
|
| 119 |
+
if existing_origin is not None:
|
| 120 |
+
# Overlaps may exist because of child nodes, but almost never to
|
| 121 |
+
# different line locations. Exception make decorated functions, where
|
| 122 |
+
# both lines are mapped to the same line in the AST.
|
| 123 |
+
|
| 124 |
+
# Line overlaps: keep bottom node.
|
| 125 |
+
if existing_origin.loc.line_loc == origin_info.loc.line_loc:
|
| 126 |
+
if existing_origin.loc.lineno >= origin_info.loc.lineno:
|
| 127 |
+
continue
|
| 128 |
+
|
| 129 |
+
# In case of column overlaps, keep the leftmost node.
|
| 130 |
+
if existing_origin.loc.col_offset <= origin_info.loc.col_offset:
|
| 131 |
+
continue
|
| 132 |
+
|
| 133 |
+
source_map[line_loc] = origin_info
|
| 134 |
+
|
| 135 |
+
except ValueError as err:
|
| 136 |
+
new_msg = 'Inconsistent ASTs detected. This is a bug. Cause: \n'
|
| 137 |
+
new_msg += str(err)
|
| 138 |
+
new_msg += 'Diff:\n'
|
| 139 |
+
|
| 140 |
+
for n, rn in zip(nodes, reparsed_nodes):
|
| 141 |
+
nodes_str = pretty_printer.fmt(n, color=False, noanno=True)
|
| 142 |
+
reparsed_nodes_str = pretty_printer.fmt(rn, color=False, noanno=True)
|
| 143 |
+
diff = difflib.context_diff(
|
| 144 |
+
nodes_str.split('\n'),
|
| 145 |
+
reparsed_nodes_str.split('\n'),
|
| 146 |
+
fromfile='Original nodes',
|
| 147 |
+
tofile='Reparsed nodes',
|
| 148 |
+
n=7)
|
| 149 |
+
diff = '\n'.join(diff)
|
| 150 |
+
new_msg += diff + '\n'
|
| 151 |
+
raise ValueError(new_msg)
|
| 152 |
+
|
| 153 |
+
return source_map
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
class _Function:
|
| 157 |
+
|
| 158 |
+
def __init__(self, name):
|
| 159 |
+
self.name = name
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
class OriginResolver(gast.NodeVisitor):
|
| 163 |
+
"""Annotates an AST with additional source information like file name."""
|
| 164 |
+
|
| 165 |
+
def __init__(self, root_node, source_lines, comments_map,
|
| 166 |
+
context_lineno, context_col_offset,
|
| 167 |
+
filepath):
|
| 168 |
+
self._source_lines = source_lines
|
| 169 |
+
self._comments_map = comments_map
|
| 170 |
+
|
| 171 |
+
if (hasattr(root_node, 'decorator_list') and root_node.decorator_list and
|
| 172 |
+
hasattr(root_node.decorator_list[0], 'lineno')):
|
| 173 |
+
# Typical case: functions. The line number of the first decorator
|
| 174 |
+
# is more accurate than the line number of the function itself in
|
| 175 |
+
# 3.8+. In earlier versions they coincide.
|
| 176 |
+
self._lineno_offset = context_lineno - root_node.decorator_list[0].lineno
|
| 177 |
+
else:
|
| 178 |
+
# Fall back to the line number of the root node.
|
| 179 |
+
self._lineno_offset = context_lineno - root_node.lineno
|
| 180 |
+
|
| 181 |
+
self._col_offset = context_col_offset - root_node.col_offset
|
| 182 |
+
|
| 183 |
+
self._filepath = filepath
|
| 184 |
+
|
| 185 |
+
self._function_stack = []
|
| 186 |
+
|
| 187 |
+
def _absolute_lineno(self, lineno):
|
| 188 |
+
return lineno + self._lineno_offset
|
| 189 |
+
|
| 190 |
+
def _absolute_col_offset(self, col_offset):
|
| 191 |
+
if col_offset is None:
|
| 192 |
+
return 0
|
| 193 |
+
return col_offset + self._col_offset
|
| 194 |
+
|
| 195 |
+
def _attach_origin_info(self, node):
|
| 196 |
+
lineno = getattr(node, 'lineno', None)
|
| 197 |
+
col_offset = getattr(node, 'col_offset', None)
|
| 198 |
+
|
| 199 |
+
if lineno is None:
|
| 200 |
+
return
|
| 201 |
+
|
| 202 |
+
if self._function_stack:
|
| 203 |
+
function_name = self._function_stack[-1].name
|
| 204 |
+
else:
|
| 205 |
+
function_name = None
|
| 206 |
+
|
| 207 |
+
source_code_line = self._source_lines[lineno - 1]
|
| 208 |
+
comment = self._comments_map.get(lineno)
|
| 209 |
+
|
| 210 |
+
loc = Location(self._filepath, self._absolute_lineno(lineno),
|
| 211 |
+
self._absolute_col_offset(col_offset))
|
| 212 |
+
origin = OriginInfo(loc, function_name, source_code_line, comment)
|
| 213 |
+
anno.setanno(node, 'lineno', lineno)
|
| 214 |
+
anno.setanno(node, anno.Basic.ORIGIN, origin)
|
| 215 |
+
|
| 216 |
+
def visit(self, node):
|
| 217 |
+
entered_function = False
|
| 218 |
+
if isinstance(node, gast.FunctionDef):
|
| 219 |
+
entered_function = True
|
| 220 |
+
self._function_stack.append(_Function(node.name))
|
| 221 |
+
|
| 222 |
+
self._attach_origin_info(node)
|
| 223 |
+
self.generic_visit(node)
|
| 224 |
+
|
| 225 |
+
if entered_function:
|
| 226 |
+
self._function_stack.pop()
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
def resolve(node, source, context_filepath, context_lineno, context_col_offset):
|
| 230 |
+
"""Adds origin information to an AST, based on the source it was loaded from.
|
| 231 |
+
|
| 232 |
+
This allows us to map the original source code line numbers to generated
|
| 233 |
+
source code.
|
| 234 |
+
|
| 235 |
+
Note: the AST may be a part of a larger context (e.g. a function is part of
|
| 236 |
+
a module that may contain other things). However, this function does not
|
| 237 |
+
assume the source argument contains the entire context, nor that it contains
|
| 238 |
+
only code corresponding to node itself. However, it assumes that node was
|
| 239 |
+
parsed from the given source code.
|
| 240 |
+
For this reason, two extra arguments are required, and they indicate the
|
| 241 |
+
location of the node in the original context.
|
| 242 |
+
|
| 243 |
+
Args:
|
| 244 |
+
node: gast.AST, the AST to annotate.
|
| 245 |
+
source: Text, the source code representing node.
|
| 246 |
+
context_filepath: Text
|
| 247 |
+
context_lineno: int
|
| 248 |
+
context_col_offset: int
|
| 249 |
+
"""
|
| 250 |
+
# TODO(mdan): Pull this to a separate utility.
|
| 251 |
+
code_reader = io.StringIO(source)
|
| 252 |
+
comments_map = {}
|
| 253 |
+
try:
|
| 254 |
+
for token in tokenize.generate_tokens(code_reader.readline):
|
| 255 |
+
tok_type, tok_string, loc, _, _ = token
|
| 256 |
+
srow, _ = loc
|
| 257 |
+
if tok_type == tokenize.COMMENT:
|
| 258 |
+
comments_map[srow] = tok_string.strip()[1:].strip()
|
| 259 |
+
except tokenize.TokenError:
|
| 260 |
+
if isinstance(node, gast.Lambda):
|
| 261 |
+
# Source code resolution in older Python versions is brittle for
|
| 262 |
+
# lambda functions, and may contain garbage.
|
| 263 |
+
pass
|
| 264 |
+
else:
|
| 265 |
+
raise
|
| 266 |
+
|
| 267 |
+
source_lines = source.split('\n')
|
| 268 |
+
visitor = OriginResolver(node, source_lines, comments_map,
|
| 269 |
+
context_lineno, context_col_offset,
|
| 270 |
+
context_filepath)
|
| 271 |
+
visitor.visit(node)
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
def resolve_entity(node, source, entity):
|
| 275 |
+
"""Like resolve, but extracts the context information from an entity."""
|
| 276 |
+
lines, lineno = tf_inspect.getsourcelines(entity)
|
| 277 |
+
filepath = tf_inspect.getsourcefile(entity)
|
| 278 |
+
|
| 279 |
+
# Poor man's attempt at guessing the column offset: count the leading
|
| 280 |
+
# whitespace. This might not work well with tabs.
|
| 281 |
+
definition_line = lines[0]
|
| 282 |
+
col_offset = len(definition_line) - len(definition_line.lstrip())
|
| 283 |
+
|
| 284 |
+
resolve(node, source, filepath, lineno, col_offset)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
def copy_origin(from_node, to_node):
|
| 288 |
+
"""Copies the origin info from a node to another, recursively."""
|
| 289 |
+
origin = anno.Basic.ORIGIN.of(from_node, default=None)
|
| 290 |
+
if origin is None:
|
| 291 |
+
return
|
| 292 |
+
if not isinstance(to_node, (list, tuple)):
|
| 293 |
+
to_node = (to_node,)
|
| 294 |
+
for node in to_node:
|
| 295 |
+
for n in gast.walk(node):
|
| 296 |
+
anno.setanno(n, anno.Basic.ORIGIN, origin)
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/parser.py
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Converting code to AST.
|
| 16 |
+
|
| 17 |
+
Adapted from Tangent.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
import ast
|
| 21 |
+
import inspect
|
| 22 |
+
import io
|
| 23 |
+
import linecache
|
| 24 |
+
import re
|
| 25 |
+
import sys
|
| 26 |
+
import textwrap
|
| 27 |
+
import tokenize
|
| 28 |
+
|
| 29 |
+
import astunparse
|
| 30 |
+
import gast
|
| 31 |
+
|
| 32 |
+
from tensorflow.python.autograph.pyct import errors
|
| 33 |
+
from tensorflow.python.autograph.pyct import inspect_utils
|
| 34 |
+
from tensorflow.python.util import tf_inspect
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
PY2_PREAMBLE = textwrap.dedent("""
|
| 38 |
+
""")
|
| 39 |
+
PY3_PREAMBLE = ''
|
| 40 |
+
MAX_SIZE = 0
|
| 41 |
+
|
| 42 |
+
if sys.version_info >= (3, 9):
|
| 43 |
+
astunparse = ast
|
| 44 |
+
|
| 45 |
+
if sys.version_info >= (3,):
|
| 46 |
+
STANDARD_PREAMBLE = PY3_PREAMBLE
|
| 47 |
+
MAX_SIZE = sys.maxsize
|
| 48 |
+
else:
|
| 49 |
+
STANDARD_PREAMBLE = PY2_PREAMBLE
|
| 50 |
+
MAX_SIZE = sys.maxint
|
| 51 |
+
|
| 52 |
+
STANDARD_PREAMBLE_LEN = STANDARD_PREAMBLE.count('__future__')
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
_LEADING_WHITESPACE = re.compile(r'\s*')
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def _unfold_continuations(code_string):
|
| 59 |
+
"""Removes any backslash line continuations from the code."""
|
| 60 |
+
return code_string.replace('\\\n', '')
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def dedent_block(code_string):
|
| 64 |
+
"""Dedents a code so that its first line starts at row zero."""
|
| 65 |
+
|
| 66 |
+
code_string = _unfold_continuations(code_string)
|
| 67 |
+
|
| 68 |
+
token_gen = tokenize.generate_tokens(io.StringIO(code_string).readline)
|
| 69 |
+
|
| 70 |
+
block_indentation = None
|
| 71 |
+
tokens = []
|
| 72 |
+
try:
|
| 73 |
+
for tok in token_gen:
|
| 74 |
+
tokens.append(tok)
|
| 75 |
+
except tokenize.TokenError:
|
| 76 |
+
# Resolution of lambda functions may yield incomplete code, which can
|
| 77 |
+
# in turn generate this error. We silently ignore this error because the
|
| 78 |
+
# parser may still be able to deal with it.
|
| 79 |
+
pass
|
| 80 |
+
|
| 81 |
+
for tok in tokens:
|
| 82 |
+
tok_type, tok_string, _, _, _ = tok
|
| 83 |
+
if tok_type == tokenize.INDENT:
|
| 84 |
+
block_indentation = tok_string
|
| 85 |
+
block_level = len(block_indentation)
|
| 86 |
+
break
|
| 87 |
+
elif tok_type not in (
|
| 88 |
+
tokenize.NL, tokenize.NEWLINE, tokenize.STRING, tokenize.COMMENT):
|
| 89 |
+
block_indentation = ''
|
| 90 |
+
break
|
| 91 |
+
|
| 92 |
+
if not block_indentation:
|
| 93 |
+
return code_string
|
| 94 |
+
|
| 95 |
+
block_level = len(block_indentation)
|
| 96 |
+
first_indent_uses_tabs = '\t' in block_indentation
|
| 97 |
+
for i, tok in enumerate(tokens):
|
| 98 |
+
tok_type, tok_string, _, _, _ = tok
|
| 99 |
+
if tok_type == tokenize.INDENT:
|
| 100 |
+
if ((' ' in tok_string and first_indent_uses_tabs)
|
| 101 |
+
or ('\t' in tok_string and not first_indent_uses_tabs)):
|
| 102 |
+
# TODO(mdan): We could attempt to convert tabs to spaces by unix rule.
|
| 103 |
+
# See:
|
| 104 |
+
# https://docs.python.org/3/reference/lexical_analysis.html#indentation
|
| 105 |
+
raise errors.UnsupportedLanguageElementError(
|
| 106 |
+
'code mixing tabs and spaces for indentation is not allowed')
|
| 107 |
+
if len(tok_string) >= block_level:
|
| 108 |
+
tok_string = tok_string[block_level:]
|
| 109 |
+
tokens[i] = (tok_type, tok_string)
|
| 110 |
+
|
| 111 |
+
new_code = tokenize.untokenize(tokens)
|
| 112 |
+
|
| 113 |
+
# Note: untokenize respects the line structure, but not the whitespace within
|
| 114 |
+
# lines. For example, `def foo()` may be untokenized as `def foo ()`
|
| 115 |
+
# So instead of using the output of dedent, we match the leading whitespace
|
| 116 |
+
# on each line.
|
| 117 |
+
dedented_code = []
|
| 118 |
+
for line, new_line in zip(code_string.split('\n'), new_code.split('\n')):
|
| 119 |
+
original_indent = re.match(_LEADING_WHITESPACE, line).group()
|
| 120 |
+
new_indent = re.match(_LEADING_WHITESPACE, new_line).group()
|
| 121 |
+
if len(original_indent) > len(new_indent):
|
| 122 |
+
dedented_line = line[len(original_indent) - len(new_indent):]
|
| 123 |
+
else:
|
| 124 |
+
dedented_line = line
|
| 125 |
+
dedented_code.append(dedented_line)
|
| 126 |
+
new_code = '\n'.join(dedented_code)
|
| 127 |
+
|
| 128 |
+
return new_code
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def parse_entity(entity, future_features):
|
| 132 |
+
"""Returns the AST and source code of given entity.
|
| 133 |
+
|
| 134 |
+
Args:
|
| 135 |
+
entity: Any, Python function/method/class
|
| 136 |
+
future_features: Iterable[Text], future features to use (e.g.
|
| 137 |
+
'print_statement'). See
|
| 138 |
+
https://docs.python.org/2/reference/simple_stmts.html#future
|
| 139 |
+
|
| 140 |
+
Returns:
|
| 141 |
+
gast.AST, Text: the parsed AST node; the source code that was parsed to
|
| 142 |
+
generate the AST (including any prefixes that this function may have added).
|
| 143 |
+
"""
|
| 144 |
+
if inspect_utils.islambda(entity):
|
| 145 |
+
return _parse_lambda(entity)
|
| 146 |
+
|
| 147 |
+
try:
|
| 148 |
+
original_source = inspect_utils.getimmediatesource(entity)
|
| 149 |
+
except OSError as e:
|
| 150 |
+
raise errors.InaccessibleSourceCodeError(
|
| 151 |
+
f'Unable to locate the source code of {entity}. Note that functions'
|
| 152 |
+
' defined in certain environments, like the interactive Python shell,'
|
| 153 |
+
' do not expose their source code. If that is the case, you should'
|
| 154 |
+
' define them in a .py source file. If you are certain the code is'
|
| 155 |
+
' graph-compatible, wrap the call using'
|
| 156 |
+
f' @tf.autograph.experimental.do_not_convert. Original error: {e}')
|
| 157 |
+
|
| 158 |
+
source = dedent_block(original_source)
|
| 159 |
+
|
| 160 |
+
future_statements = tuple(
|
| 161 |
+
'from __future__ import {}'.format(name) for name in future_features)
|
| 162 |
+
source = '\n'.join(future_statements + (source,))
|
| 163 |
+
|
| 164 |
+
return parse(source, preamble_len=len(future_features)), source
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def _without_context(node, lines, minl, maxl):
|
| 168 |
+
"""Returns a clean node and source code without indenting and context."""
|
| 169 |
+
for n in gast.walk(node):
|
| 170 |
+
lineno = getattr(n, 'lineno', None)
|
| 171 |
+
if lineno is not None:
|
| 172 |
+
n.lineno = lineno - minl
|
| 173 |
+
end_lineno = getattr(n, 'end_lineno', None)
|
| 174 |
+
if end_lineno is not None:
|
| 175 |
+
n.end_lineno = end_lineno - minl
|
| 176 |
+
|
| 177 |
+
code_lines = lines[minl - 1:maxl]
|
| 178 |
+
|
| 179 |
+
# Attempt to clean up surrounding context code.
|
| 180 |
+
|
| 181 |
+
end_col_offset = getattr(node, 'end_col_offset', None)
|
| 182 |
+
if end_col_offset is not None:
|
| 183 |
+
# This is only available in 3.8.
|
| 184 |
+
code_lines[-1] = code_lines[-1][:end_col_offset]
|
| 185 |
+
|
| 186 |
+
col_offset = getattr(node, 'col_offset', None)
|
| 187 |
+
if col_offset is None:
|
| 188 |
+
# Older Python: try to find the "lambda" token. This is brittle.
|
| 189 |
+
match = re.search(r'(?<!\w)lambda(?!\w)', code_lines[0])
|
| 190 |
+
if match is not None:
|
| 191 |
+
col_offset = match.start(0)
|
| 192 |
+
|
| 193 |
+
if col_offset is not None:
|
| 194 |
+
code_lines[0] = code_lines[0][col_offset:]
|
| 195 |
+
|
| 196 |
+
code_block = '\n'.join([c.rstrip() for c in code_lines])
|
| 197 |
+
|
| 198 |
+
return node, code_block
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def _arg_name(node):
|
| 202 |
+
if node is None:
|
| 203 |
+
return None
|
| 204 |
+
if isinstance(node, gast.Name):
|
| 205 |
+
return node.id
|
| 206 |
+
assert isinstance(node, str)
|
| 207 |
+
return node
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def _node_matches_argspec(node, func):
|
| 211 |
+
"""Returns True is node fits the argspec of func."""
|
| 212 |
+
# TODO(mdan): Use just inspect once support for Python 2 is dropped.
|
| 213 |
+
arg_spec = tf_inspect.getfullargspec(func)
|
| 214 |
+
|
| 215 |
+
node_args = tuple(_arg_name(arg) for arg in node.args.args)
|
| 216 |
+
if node_args != tuple(arg_spec.args):
|
| 217 |
+
return False
|
| 218 |
+
|
| 219 |
+
if arg_spec.varargs != _arg_name(node.args.vararg):
|
| 220 |
+
return False
|
| 221 |
+
|
| 222 |
+
if arg_spec.varkw != _arg_name(node.args.kwarg):
|
| 223 |
+
return False
|
| 224 |
+
|
| 225 |
+
node_kwonlyargs = tuple(_arg_name(arg) for arg in node.args.kwonlyargs)
|
| 226 |
+
if node_kwonlyargs != tuple(arg_spec.kwonlyargs):
|
| 227 |
+
return False
|
| 228 |
+
|
| 229 |
+
return True
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
def _parse_lambda(lam):
|
| 233 |
+
"""Returns the AST and source code of given lambda function.
|
| 234 |
+
|
| 235 |
+
Args:
|
| 236 |
+
lam: types.LambdaType, Python function/method/class
|
| 237 |
+
|
| 238 |
+
Returns:
|
| 239 |
+
gast.AST, Text: the parsed AST node; the source code that was parsed to
|
| 240 |
+
generate the AST (including any prefixes that this function may have added).
|
| 241 |
+
"""
|
| 242 |
+
# TODO(mdan): Use a fast path if the definition is not multi-line.
|
| 243 |
+
# We could detect that the lambda is in a multi-line expression by looking
|
| 244 |
+
# at the surrounding code - an surrounding set of parentheses indicates a
|
| 245 |
+
# potential multi-line definition.
|
| 246 |
+
|
| 247 |
+
mod = inspect.getmodule(lam)
|
| 248 |
+
f = inspect.getsourcefile(lam)
|
| 249 |
+
def_line = lam.__code__.co_firstlineno
|
| 250 |
+
|
| 251 |
+
# This method is more robust that just calling inspect.getsource(mod), as it
|
| 252 |
+
# works in interactive shells, where getsource would fail. This is the
|
| 253 |
+
# same procedure followed by inspect for non-modules:
|
| 254 |
+
# https://github.com/python/cpython/blob/3.8/Lib/inspect.py#L772
|
| 255 |
+
lines = linecache.getlines(f, mod.__dict__)
|
| 256 |
+
source = ''.join(lines)
|
| 257 |
+
|
| 258 |
+
# Narrow down to the last node starting before our definition node.
|
| 259 |
+
all_nodes = parse(source, preamble_len=0, single_node=False)
|
| 260 |
+
search_nodes = []
|
| 261 |
+
for node in all_nodes:
|
| 262 |
+
# Also include nodes without a line number, for safety. This is defensive -
|
| 263 |
+
# we don't know whether such nodes might exist, and if they do, whether
|
| 264 |
+
# they are not safe to skip.
|
| 265 |
+
# TODO(mdan): Replace this check with an assertion or skip such nodes.
|
| 266 |
+
if getattr(node, 'lineno', def_line) <= def_line:
|
| 267 |
+
search_nodes.append(node)
|
| 268 |
+
else:
|
| 269 |
+
# Found a node starting past our lambda - can stop the search.
|
| 270 |
+
break
|
| 271 |
+
|
| 272 |
+
# Extract all lambda nodes from the shortlist.
|
| 273 |
+
lambda_nodes = []
|
| 274 |
+
for node in search_nodes:
|
| 275 |
+
lambda_nodes.extend(
|
| 276 |
+
n for n in gast.walk(node) if isinstance(n, gast.Lambda))
|
| 277 |
+
|
| 278 |
+
# Filter down to lambda nodes which span our actual lambda.
|
| 279 |
+
candidates = []
|
| 280 |
+
for ln in lambda_nodes:
|
| 281 |
+
minl, maxl = MAX_SIZE, 0
|
| 282 |
+
for n in gast.walk(ln):
|
| 283 |
+
minl = min(minl, getattr(n, 'lineno', minl))
|
| 284 |
+
lineno = getattr(n, 'lineno', maxl)
|
| 285 |
+
end_lineno = getattr(n, 'end_lineno', None)
|
| 286 |
+
if end_lineno is not None:
|
| 287 |
+
# end_lineno is more precise, but lineno should almost always work too.
|
| 288 |
+
lineno = end_lineno
|
| 289 |
+
maxl = max(maxl, lineno)
|
| 290 |
+
if minl <= def_line <= maxl:
|
| 291 |
+
candidates.append((ln, minl, maxl))
|
| 292 |
+
|
| 293 |
+
# Happy path: exactly one node found.
|
| 294 |
+
if len(candidates) == 1:
|
| 295 |
+
(node, minl, maxl), = candidates # pylint:disable=unbalanced-tuple-unpacking
|
| 296 |
+
return _without_context(node, lines, minl, maxl)
|
| 297 |
+
|
| 298 |
+
elif not candidates:
|
| 299 |
+
lambda_codes = '\n'.join([unparse(l) for l in lambda_nodes])
|
| 300 |
+
raise errors.UnsupportedLanguageElementError(
|
| 301 |
+
f'could not parse the source code of {lam}:'
|
| 302 |
+
f' no matching AST found among candidates:\n{lambda_codes}')
|
| 303 |
+
|
| 304 |
+
# Attempt to narrow down selection by signature is multiple nodes are found.
|
| 305 |
+
matches = [v for v in candidates if _node_matches_argspec(v[0], lam)]
|
| 306 |
+
if len(matches) == 1:
|
| 307 |
+
(node, minl, maxl), = matches
|
| 308 |
+
return _without_context(node, lines, minl, maxl)
|
| 309 |
+
|
| 310 |
+
# Give up if could not narrow down to a single node.
|
| 311 |
+
matches = '\n'.join(
|
| 312 |
+
'Match {}:\n{}\n'.format(i, unparse(node, include_encoding_marker=False))
|
| 313 |
+
for i, (node, _, _) in enumerate(matches))
|
| 314 |
+
raise errors.UnsupportedLanguageElementError(
|
| 315 |
+
f'could not parse the source code of {lam}: found multiple definitions'
|
| 316 |
+
' with identical signatures at the location. This error'
|
| 317 |
+
' may be avoided by defining each lambda on a single line and with'
|
| 318 |
+
f' unique argument names. The matching definitions were:\n{matches}')
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
# TODO(mdan): This should take futures as input instead.
|
| 322 |
+
def parse(src, preamble_len=0, single_node=True):
|
| 323 |
+
"""Returns the AST of given piece of code.
|
| 324 |
+
|
| 325 |
+
Args:
|
| 326 |
+
src: Text
|
| 327 |
+
preamble_len: Int, indicates leading nodes in the parsed AST which should be
|
| 328 |
+
dropped.
|
| 329 |
+
single_node: Bool, whether `src` is assumed to be represented by exactly one
|
| 330 |
+
AST node.
|
| 331 |
+
|
| 332 |
+
Returns:
|
| 333 |
+
ast.AST
|
| 334 |
+
"""
|
| 335 |
+
module_node = gast.parse(src)
|
| 336 |
+
nodes = module_node.body
|
| 337 |
+
if preamble_len:
|
| 338 |
+
nodes = nodes[preamble_len:]
|
| 339 |
+
if single_node:
|
| 340 |
+
if len(nodes) != 1:
|
| 341 |
+
raise ValueError('expected exactly one node, got {}'.format(nodes))
|
| 342 |
+
return nodes[0]
|
| 343 |
+
return nodes
|
| 344 |
+
|
| 345 |
+
|
| 346 |
+
def parse_expression(src):
|
| 347 |
+
"""Returns the AST of given identifier.
|
| 348 |
+
|
| 349 |
+
Args:
|
| 350 |
+
src: A piece of code that represents a single Python expression
|
| 351 |
+
Returns:
|
| 352 |
+
A gast.AST object.
|
| 353 |
+
Raises:
|
| 354 |
+
ValueError: if src does not consist of a single Expression.
|
| 355 |
+
"""
|
| 356 |
+
src = STANDARD_PREAMBLE + src.strip()
|
| 357 |
+
node = parse(src, preamble_len=STANDARD_PREAMBLE_LEN, single_node=True)
|
| 358 |
+
if __debug__:
|
| 359 |
+
if not isinstance(node, gast.Expr):
|
| 360 |
+
raise ValueError(
|
| 361 |
+
'expected exactly one node of type Expr, got {}'.format(node))
|
| 362 |
+
return node.value
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
def unparse(node, indentation=None, include_encoding_marker=True):
|
| 366 |
+
"""Returns the source code of given AST.
|
| 367 |
+
|
| 368 |
+
Args:
|
| 369 |
+
node: The code to compile, as an AST object.
|
| 370 |
+
indentation: Unused, deprecated. The returning code will always be indented
|
| 371 |
+
at 4 spaces.
|
| 372 |
+
include_encoding_marker: Bool, whether to include a comment on the first
|
| 373 |
+
line to explicitly specify UTF-8 encoding.
|
| 374 |
+
|
| 375 |
+
Returns:
|
| 376 |
+
code: The source code generated from the AST object
|
| 377 |
+
source_mapping: A mapping between the user and AutoGraph generated code.
|
| 378 |
+
"""
|
| 379 |
+
del indentation # astunparse doesn't allow configuring it.
|
| 380 |
+
if not isinstance(node, (list, tuple)):
|
| 381 |
+
node = (node,)
|
| 382 |
+
|
| 383 |
+
codes = []
|
| 384 |
+
if include_encoding_marker:
|
| 385 |
+
codes.append('# coding=utf-8')
|
| 386 |
+
for n in node:
|
| 387 |
+
if isinstance(n, gast.AST):
|
| 388 |
+
ast_n = gast.gast_to_ast(n)
|
| 389 |
+
else:
|
| 390 |
+
ast_n = n
|
| 391 |
+
|
| 392 |
+
if astunparse is ast:
|
| 393 |
+
ast.fix_missing_locations(ast_n) # Only ast needs to call this.
|
| 394 |
+
codes.append(astunparse.unparse(ast_n).strip())
|
| 395 |
+
|
| 396 |
+
return '\n'.join(codes)
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/pretty_printer.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Print an AST tree in a form more readable than ast.dump."""
|
| 16 |
+
|
| 17 |
+
import gast
|
| 18 |
+
import termcolor
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class PrettyPrinter(gast.NodeVisitor):
|
| 22 |
+
"""Print AST nodes."""
|
| 23 |
+
|
| 24 |
+
def __init__(self, color, noanno):
|
| 25 |
+
self.indent_lvl = 0
|
| 26 |
+
self.result = ''
|
| 27 |
+
self.color = color
|
| 28 |
+
self.noanno = noanno
|
| 29 |
+
|
| 30 |
+
def _color(self, string, color, attrs=None):
|
| 31 |
+
if self.color:
|
| 32 |
+
return termcolor.colored(string, color, attrs=attrs)
|
| 33 |
+
return string
|
| 34 |
+
|
| 35 |
+
def _type(self, node):
|
| 36 |
+
return self._color(node.__class__.__name__, None, ['bold'])
|
| 37 |
+
|
| 38 |
+
def _field(self, name):
|
| 39 |
+
return self._color(name, 'blue')
|
| 40 |
+
|
| 41 |
+
def _value(self, name):
|
| 42 |
+
return self._color(name, 'magenta')
|
| 43 |
+
|
| 44 |
+
def _warning(self, name):
|
| 45 |
+
return self._color(name, 'red')
|
| 46 |
+
|
| 47 |
+
def _indent(self):
|
| 48 |
+
return self._color('| ' * self.indent_lvl, None, ['dark'])
|
| 49 |
+
|
| 50 |
+
def _print(self, s):
|
| 51 |
+
self.result += s
|
| 52 |
+
self.result += '\n'
|
| 53 |
+
|
| 54 |
+
def generic_visit(self, node, name=None):
|
| 55 |
+
# In very rare instances, a list can contain something other than a Node.
|
| 56 |
+
# e.g. Global contains a list of strings.
|
| 57 |
+
if isinstance(node, str):
|
| 58 |
+
if name:
|
| 59 |
+
self._print('%s%s="%s"' % (self._indent(), name, node))
|
| 60 |
+
else:
|
| 61 |
+
self._print('%s"%s"' % (self._indent(), node))
|
| 62 |
+
return
|
| 63 |
+
|
| 64 |
+
if node._fields:
|
| 65 |
+
cont = ':'
|
| 66 |
+
else:
|
| 67 |
+
cont = '()'
|
| 68 |
+
|
| 69 |
+
if name:
|
| 70 |
+
self._print('%s%s=%s%s' % (self._indent(), self._field(name),
|
| 71 |
+
self._type(node), cont))
|
| 72 |
+
else:
|
| 73 |
+
self._print('%s%s%s' % (self._indent(), self._type(node), cont))
|
| 74 |
+
|
| 75 |
+
self.indent_lvl += 1
|
| 76 |
+
for f in node._fields:
|
| 77 |
+
if self.noanno and f.startswith('__'):
|
| 78 |
+
continue
|
| 79 |
+
if not hasattr(node, f):
|
| 80 |
+
self._print('%s%s' % (self._indent(), self._warning('%s=<unset>' % f)))
|
| 81 |
+
continue
|
| 82 |
+
v = getattr(node, f)
|
| 83 |
+
if isinstance(v, list):
|
| 84 |
+
if v:
|
| 85 |
+
self._print('%s%s=[' % (self._indent(), self._field(f)))
|
| 86 |
+
self.indent_lvl += 1
|
| 87 |
+
for n in v:
|
| 88 |
+
if n is not None:
|
| 89 |
+
self.generic_visit(n)
|
| 90 |
+
else:
|
| 91 |
+
self._print('%sNone' % (self._indent()))
|
| 92 |
+
self.indent_lvl -= 1
|
| 93 |
+
self._print('%s]' % (self._indent()))
|
| 94 |
+
else:
|
| 95 |
+
self._print('%s%s=[]' % (self._indent(), self._field(f)))
|
| 96 |
+
elif isinstance(v, tuple):
|
| 97 |
+
if v:
|
| 98 |
+
self._print('%s%s=(' % (self._indent(), self._field(f)))
|
| 99 |
+
self.indent_lvl += 1
|
| 100 |
+
for n in v:
|
| 101 |
+
if n is not None:
|
| 102 |
+
self.generic_visit(n)
|
| 103 |
+
else:
|
| 104 |
+
self._print('%sNone' % (self._indent()))
|
| 105 |
+
self.indent_lvl -= 1
|
| 106 |
+
self._print('%s)' % (self._indent()))
|
| 107 |
+
else:
|
| 108 |
+
self._print('%s%s=()' % (self._indent(), self._field(f)))
|
| 109 |
+
elif isinstance(v, gast.AST):
|
| 110 |
+
self.generic_visit(v, f)
|
| 111 |
+
elif isinstance(v, bytes):
|
| 112 |
+
self._print('%s%s=%s' % (self._indent(), self._field(f),
|
| 113 |
+
self._value('b"%s"' % v)))
|
| 114 |
+
elif isinstance(v, str):
|
| 115 |
+
self._print('%s%s=%s' % (self._indent(), self._field(f),
|
| 116 |
+
self._value('u"%s"' % v)))
|
| 117 |
+
else:
|
| 118 |
+
self._print('%s%s=%s' % (self._indent(), self._field(f),
|
| 119 |
+
self._value(v)))
|
| 120 |
+
self.indent_lvl -= 1
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def fmt(node, color=True, noanno=False):
|
| 124 |
+
printer = PrettyPrinter(color, noanno)
|
| 125 |
+
if isinstance(node, (list, tuple)):
|
| 126 |
+
for n in node:
|
| 127 |
+
printer.visit(n)
|
| 128 |
+
else:
|
| 129 |
+
printer.visit(node)
|
| 130 |
+
return printer.result
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/qual_names.py
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Utilities for manipulating qualified names.
|
| 16 |
+
|
| 17 |
+
A qualified name is a uniform way to refer to simple (e.g. 'foo') and composite
|
| 18 |
+
(e.g. 'foo.bar') syntactic symbols.
|
| 19 |
+
|
| 20 |
+
This is *not* related to the __qualname__ attribute used by inspect, which
|
| 21 |
+
refers to scopes.
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
import collections
|
| 25 |
+
|
| 26 |
+
import gast
|
| 27 |
+
|
| 28 |
+
from tensorflow.python.autograph.pyct import anno
|
| 29 |
+
from tensorflow.python.autograph.pyct import parser
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
class CallerMustSetThis(object):
|
| 33 |
+
pass
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
class Symbol(collections.namedtuple('Symbol', ['name'])):
|
| 37 |
+
"""Represents a Python symbol."""
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class Literal(collections.namedtuple('Literal', ['value'])):
|
| 41 |
+
"""Represents a Python numeric literal."""
|
| 42 |
+
|
| 43 |
+
def __str__(self):
|
| 44 |
+
if isinstance(self.value, str):
|
| 45 |
+
return "'{}'".format(self.value)
|
| 46 |
+
return str(self.value)
|
| 47 |
+
|
| 48 |
+
def __repr__(self):
|
| 49 |
+
return str(self)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
# TODO(mdan): Use subclasses to remove the has_attr has_subscript booleans.
|
| 53 |
+
class QN(object):
|
| 54 |
+
"""Represents a qualified name."""
|
| 55 |
+
|
| 56 |
+
def __init__(self, base, attr=None, subscript=None):
|
| 57 |
+
if attr is not None and subscript is not None:
|
| 58 |
+
raise ValueError('A QN can only be either an attr or a subscript, not '
|
| 59 |
+
'both: attr={}, subscript={}.'.format(attr, subscript))
|
| 60 |
+
self._has_attr = False
|
| 61 |
+
self._has_subscript = False
|
| 62 |
+
|
| 63 |
+
if attr is not None:
|
| 64 |
+
if not isinstance(base, QN):
|
| 65 |
+
raise ValueError(
|
| 66 |
+
'for attribute QNs, base must be a QN; got instead "%s"' % base)
|
| 67 |
+
if not isinstance(attr, str):
|
| 68 |
+
raise ValueError('attr may only be a string; got instead "%s"' % attr)
|
| 69 |
+
self._parent = base
|
| 70 |
+
# TODO(mdan): Get rid of the tuple - it can only have 1 or 2 elements now.
|
| 71 |
+
self.qn = (base, attr)
|
| 72 |
+
self._has_attr = True
|
| 73 |
+
|
| 74 |
+
elif subscript is not None:
|
| 75 |
+
if not isinstance(base, QN):
|
| 76 |
+
raise ValueError('For subscript QNs, base must be a QN.')
|
| 77 |
+
self._parent = base
|
| 78 |
+
self.qn = (base, subscript)
|
| 79 |
+
self._has_subscript = True
|
| 80 |
+
|
| 81 |
+
else:
|
| 82 |
+
if not isinstance(base, (str, Literal)):
|
| 83 |
+
# TODO(mdan): Require Symbol instead of string.
|
| 84 |
+
raise ValueError(
|
| 85 |
+
'for simple QNs, base must be a string or a Literal object;'
|
| 86 |
+
' got instead "%s"' % type(base))
|
| 87 |
+
assert '.' not in base and '[' not in base and ']' not in base
|
| 88 |
+
self._parent = None
|
| 89 |
+
self.qn = (base,)
|
| 90 |
+
|
| 91 |
+
def is_symbol(self):
|
| 92 |
+
return isinstance(self.qn[0], str)
|
| 93 |
+
|
| 94 |
+
def is_simple(self):
|
| 95 |
+
return len(self.qn) <= 1
|
| 96 |
+
|
| 97 |
+
def is_composite(self):
|
| 98 |
+
return len(self.qn) > 1
|
| 99 |
+
|
| 100 |
+
def has_subscript(self):
|
| 101 |
+
return self._has_subscript
|
| 102 |
+
|
| 103 |
+
def has_attr(self):
|
| 104 |
+
return self._has_attr
|
| 105 |
+
|
| 106 |
+
@property
|
| 107 |
+
def attr(self):
|
| 108 |
+
if not self._has_attr:
|
| 109 |
+
raise ValueError('Cannot get attr of non-attribute "%s".' % self)
|
| 110 |
+
return self.qn[1]
|
| 111 |
+
|
| 112 |
+
@property
|
| 113 |
+
def parent(self):
|
| 114 |
+
if self._parent is None:
|
| 115 |
+
raise ValueError('Cannot get parent of simple name "%s".' % self.qn[0])
|
| 116 |
+
return self._parent
|
| 117 |
+
|
| 118 |
+
@property
|
| 119 |
+
def owner_set(self):
|
| 120 |
+
"""Returns all the symbols (simple or composite) that own this QN.
|
| 121 |
+
|
| 122 |
+
In other words, if this symbol was modified, the symbols in the owner set
|
| 123 |
+
may also be affected.
|
| 124 |
+
|
| 125 |
+
Examples:
|
| 126 |
+
'a.b[c.d]' has two owners, 'a' and 'a.b'
|
| 127 |
+
"""
|
| 128 |
+
owners = set()
|
| 129 |
+
if self.has_attr() or self.has_subscript():
|
| 130 |
+
owners.add(self.parent)
|
| 131 |
+
owners.update(self.parent.owner_set)
|
| 132 |
+
return owners
|
| 133 |
+
|
| 134 |
+
@property
|
| 135 |
+
def support_set(self):
|
| 136 |
+
"""Returns the set of simple symbols that this QN relies on.
|
| 137 |
+
|
| 138 |
+
This would be the smallest set of symbols necessary for the QN to
|
| 139 |
+
statically resolve (assuming properties and index ranges are verified
|
| 140 |
+
at runtime).
|
| 141 |
+
|
| 142 |
+
Examples:
|
| 143 |
+
'a.b' has only one support symbol, 'a'
|
| 144 |
+
'a[i]' has two support symbols, 'a' and 'i'
|
| 145 |
+
"""
|
| 146 |
+
# TODO(mdan): This might be the set of Name nodes in the AST. Track those?
|
| 147 |
+
roots = set()
|
| 148 |
+
if self.has_attr():
|
| 149 |
+
roots.update(self.parent.support_set)
|
| 150 |
+
elif self.has_subscript():
|
| 151 |
+
roots.update(self.parent.support_set)
|
| 152 |
+
roots.update(self.qn[1].support_set)
|
| 153 |
+
else:
|
| 154 |
+
roots.add(self)
|
| 155 |
+
return roots
|
| 156 |
+
|
| 157 |
+
def __hash__(self):
|
| 158 |
+
return hash(self.qn + (self._has_attr, self._has_subscript))
|
| 159 |
+
|
| 160 |
+
def __eq__(self, other):
|
| 161 |
+
return (isinstance(other, QN) and self.qn == other.qn and
|
| 162 |
+
self.has_subscript() == other.has_subscript() and
|
| 163 |
+
self.has_attr() == other.has_attr())
|
| 164 |
+
|
| 165 |
+
def __lt__(self, other):
|
| 166 |
+
return str(self) < str(other)
|
| 167 |
+
|
| 168 |
+
def __gt__(self, other):
|
| 169 |
+
return str(self) > str(other)
|
| 170 |
+
|
| 171 |
+
def __str__(self):
|
| 172 |
+
root = self.qn[0]
|
| 173 |
+
if self.has_subscript():
|
| 174 |
+
return '{}[{}]'.format(root, self.qn[1])
|
| 175 |
+
if self.has_attr():
|
| 176 |
+
return '.'.join(map(str, self.qn))
|
| 177 |
+
else:
|
| 178 |
+
return str(root)
|
| 179 |
+
|
| 180 |
+
def __repr__(self):
|
| 181 |
+
return str(self)
|
| 182 |
+
|
| 183 |
+
def ssf(self):
|
| 184 |
+
"""Simple symbol form."""
|
| 185 |
+
ssfs = [n.ssf() if isinstance(n, QN) else n for n in self.qn]
|
| 186 |
+
ssf_string = ''
|
| 187 |
+
for i in range(0, len(self.qn) - 1):
|
| 188 |
+
if self.has_subscript():
|
| 189 |
+
delimiter = '_sub_'
|
| 190 |
+
else:
|
| 191 |
+
delimiter = '_'
|
| 192 |
+
ssf_string += ssfs[i] + delimiter
|
| 193 |
+
return ssf_string + ssfs[-1]
|
| 194 |
+
|
| 195 |
+
def ast(self):
|
| 196 |
+
"""AST representation."""
|
| 197 |
+
# The caller must adjust the context appropriately.
|
| 198 |
+
if self.has_subscript():
|
| 199 |
+
return gast.Subscript(
|
| 200 |
+
value=self.parent.ast(),
|
| 201 |
+
slice=self.qn[-1].ast(),
|
| 202 |
+
ctx=CallerMustSetThis)
|
| 203 |
+
if self.has_attr():
|
| 204 |
+
return gast.Attribute(
|
| 205 |
+
value=self.parent.ast(), attr=self.qn[-1], ctx=CallerMustSetThis)
|
| 206 |
+
|
| 207 |
+
base = self.qn[0]
|
| 208 |
+
if isinstance(base, str):
|
| 209 |
+
return gast.Name(
|
| 210 |
+
base, ctx=CallerMustSetThis, annotation=None, type_comment=None)
|
| 211 |
+
elif isinstance(base, Literal):
|
| 212 |
+
return gast.Constant(base.value, kind=None)
|
| 213 |
+
else:
|
| 214 |
+
assert False, ('the constructor should prevent types other than '
|
| 215 |
+
'str and Literal')
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
class QnResolver(gast.NodeTransformer):
|
| 219 |
+
"""Annotates nodes with QN information.
|
| 220 |
+
|
| 221 |
+
Note: Not using NodeAnnos to avoid circular dependencies.
|
| 222 |
+
"""
|
| 223 |
+
|
| 224 |
+
def visit_Name(self, node):
|
| 225 |
+
node = self.generic_visit(node)
|
| 226 |
+
anno.setanno(node, anno.Basic.QN, QN(node.id))
|
| 227 |
+
return node
|
| 228 |
+
|
| 229 |
+
def visit_Attribute(self, node):
|
| 230 |
+
node = self.generic_visit(node)
|
| 231 |
+
if anno.hasanno(node.value, anno.Basic.QN):
|
| 232 |
+
anno.setanno(node, anno.Basic.QN,
|
| 233 |
+
QN(anno.getanno(node.value, anno.Basic.QN), attr=node.attr))
|
| 234 |
+
return node
|
| 235 |
+
|
| 236 |
+
def visit_Subscript(self, node):
|
| 237 |
+
# TODO(mdan): This may no longer apply if we overload getitem.
|
| 238 |
+
node = self.generic_visit(node)
|
| 239 |
+
s = node.slice
|
| 240 |
+
if isinstance(s, (gast.Tuple, gast.Slice)):
|
| 241 |
+
# TODO(mdan): Support range and multi-dimensional indices.
|
| 242 |
+
# Continuing silently because some demos use these.
|
| 243 |
+
return node
|
| 244 |
+
if isinstance(s, gast.Constant) and s.value != Ellipsis:
|
| 245 |
+
subscript = QN(Literal(s.value))
|
| 246 |
+
else:
|
| 247 |
+
# The index may be an expression, case in which a name doesn't make sense.
|
| 248 |
+
if anno.hasanno(s, anno.Basic.QN):
|
| 249 |
+
subscript = anno.getanno(s, anno.Basic.QN)
|
| 250 |
+
else:
|
| 251 |
+
return node
|
| 252 |
+
if anno.hasanno(node.value, anno.Basic.QN):
|
| 253 |
+
anno.setanno(node, anno.Basic.QN,
|
| 254 |
+
QN(anno.getanno(node.value, anno.Basic.QN),
|
| 255 |
+
subscript=subscript))
|
| 256 |
+
return node
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
def resolve(node):
|
| 260 |
+
return QnResolver().visit(node)
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
def from_str(qn_str):
|
| 264 |
+
node = parser.parse_expression(qn_str)
|
| 265 |
+
node = resolve(node)
|
| 266 |
+
return anno.getanno(node, anno.Basic.QN)
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/templates.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""AST conversion templates.
|
| 16 |
+
|
| 17 |
+
Adapted from Tangent.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
import ast
|
| 21 |
+
import textwrap
|
| 22 |
+
|
| 23 |
+
import gast
|
| 24 |
+
|
| 25 |
+
from tensorflow.python.autograph.pyct import anno
|
| 26 |
+
from tensorflow.python.autograph.pyct import ast_util
|
| 27 |
+
from tensorflow.python.autograph.pyct import parser
|
| 28 |
+
from tensorflow.python.autograph.pyct import qual_names
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class ContextAdjuster(gast.NodeTransformer):
|
| 32 |
+
"""Adjusts the ctx field of nodes to ensure consistency.
|
| 33 |
+
|
| 34 |
+
This transformer can change the ctx fields of a variable, tuple and other
|
| 35 |
+
AST elements that allow one, based on whether the element is being read or
|
| 36 |
+
written.
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
def __init__(self, override_value):
|
| 40 |
+
self._ctx_override = override_value
|
| 41 |
+
|
| 42 |
+
def visit(self, node):
|
| 43 |
+
original_override = self._ctx_override
|
| 44 |
+
node = super(ContextAdjuster, self).visit(node)
|
| 45 |
+
if hasattr(node, 'ctx'):
|
| 46 |
+
assert node.ctx is not None, 'node {} has ctx unset'.format(node)
|
| 47 |
+
self._ctx_override = original_override
|
| 48 |
+
return node
|
| 49 |
+
|
| 50 |
+
def _apply_override(self, node):
|
| 51 |
+
if self._ctx_override is not None:
|
| 52 |
+
node.ctx = self._ctx_override()
|
| 53 |
+
|
| 54 |
+
def visit_Attribute(self, node):
|
| 55 |
+
self._apply_override(node)
|
| 56 |
+
self._ctx_override = gast.Load
|
| 57 |
+
node = self.generic_visit(node)
|
| 58 |
+
return node
|
| 59 |
+
|
| 60 |
+
def visit_Tuple(self, node):
|
| 61 |
+
self._apply_override(node)
|
| 62 |
+
return self.generic_visit(node)
|
| 63 |
+
|
| 64 |
+
def visit_List(self, node):
|
| 65 |
+
self._apply_override(node)
|
| 66 |
+
return self.generic_visit(node)
|
| 67 |
+
|
| 68 |
+
def visit_Name(self, node):
|
| 69 |
+
self._apply_override(node)
|
| 70 |
+
return self.generic_visit(node)
|
| 71 |
+
|
| 72 |
+
def visit_Call(self, node):
|
| 73 |
+
self._apply_override(node)
|
| 74 |
+
# We may be able to override these to Load(), but for now it's simpler
|
| 75 |
+
# to just assert that they're set.
|
| 76 |
+
self._ctx_override = None
|
| 77 |
+
return self.generic_visit(node)
|
| 78 |
+
|
| 79 |
+
def visit_Dict(self, node):
|
| 80 |
+
# We may be able to override these to Load(), but for now it's simpler
|
| 81 |
+
# to just assert that they're set.
|
| 82 |
+
self._ctx_override = None
|
| 83 |
+
return self.generic_visit(node)
|
| 84 |
+
|
| 85 |
+
def visit_Subscript(self, node):
|
| 86 |
+
self._apply_override(node)
|
| 87 |
+
self._ctx_override = gast.Load
|
| 88 |
+
node.value = self.visit(node.value)
|
| 89 |
+
return self.generic_visit(node)
|
| 90 |
+
|
| 91 |
+
def visit_comprehension(self, node):
|
| 92 |
+
# We may be able to override some of these, but for now it's simpler
|
| 93 |
+
# to just assert that they're set.
|
| 94 |
+
self._ctx_override = None
|
| 95 |
+
return self.generic_visit(node)
|
| 96 |
+
|
| 97 |
+
def visit_Lambda(self, node):
|
| 98 |
+
# We may be able to override some of these, but for now it's simpler
|
| 99 |
+
# to just assert that they're set.
|
| 100 |
+
self._ctx_override = None
|
| 101 |
+
return self.generic_visit(node)
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class ReplaceTransformer(gast.NodeTransformer):
|
| 105 |
+
"""Replace AST nodes."""
|
| 106 |
+
|
| 107 |
+
def __init__(self, replacements):
|
| 108 |
+
"""Create a new ReplaceTransformer.
|
| 109 |
+
|
| 110 |
+
Args:
|
| 111 |
+
replacements: A mapping from placeholder names to (lists of) AST nodes
|
| 112 |
+
that these placeholders will be replaced by.
|
| 113 |
+
"""
|
| 114 |
+
self.replacements = replacements
|
| 115 |
+
self.in_replacements = False
|
| 116 |
+
self.preserved_annos = {
|
| 117 |
+
anno.Basic.DIRECTIVES,
|
| 118 |
+
anno.Basic.EXTRA_LOOP_TEST,
|
| 119 |
+
anno.Basic.ORIGIN,
|
| 120 |
+
anno.Basic.SKIP_PROCESSING,
|
| 121 |
+
anno.Static.ORIG_DEFINITIONS,
|
| 122 |
+
'function_context_name',
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
def _prepare_replacement(self, replaced, key):
|
| 126 |
+
"""Prepares a replacement AST that's safe to swap in for a node.
|
| 127 |
+
|
| 128 |
+
Args:
|
| 129 |
+
replaced: ast.AST, the node being replaced
|
| 130 |
+
key: Hashable, the key of the replacement AST
|
| 131 |
+
Returns:
|
| 132 |
+
ast.AST, the replacement AST
|
| 133 |
+
"""
|
| 134 |
+
repl = self.replacements[key]
|
| 135 |
+
|
| 136 |
+
new_nodes = ast_util.copy_clean(repl, preserve_annos=self.preserved_annos)
|
| 137 |
+
if isinstance(new_nodes, gast.AST):
|
| 138 |
+
new_nodes = [new_nodes]
|
| 139 |
+
|
| 140 |
+
return new_nodes
|
| 141 |
+
|
| 142 |
+
def visit_Expr(self, node):
|
| 143 |
+
# When replacing a placeholder with an entire statement, the replacement
|
| 144 |
+
# must stand on its own and not be wrapped in an Expr.
|
| 145 |
+
new_value = self.visit(node.value)
|
| 146 |
+
if new_value is node.value:
|
| 147 |
+
return node
|
| 148 |
+
return new_value
|
| 149 |
+
|
| 150 |
+
def visit_keyword(self, node):
|
| 151 |
+
if node.arg not in self.replacements:
|
| 152 |
+
return self.generic_visit(node)
|
| 153 |
+
|
| 154 |
+
repl = self._prepare_replacement(node, node.arg)
|
| 155 |
+
if isinstance(repl, gast.keyword):
|
| 156 |
+
return repl
|
| 157 |
+
elif (repl and isinstance(repl, (list, tuple)) and
|
| 158 |
+
all(isinstance(r, gast.keyword) for r in repl)):
|
| 159 |
+
return repl
|
| 160 |
+
# TODO(mdan): We may allow replacing with a string as well.
|
| 161 |
+
# For example, if one wanted to replace foo with bar in foo=baz, then
|
| 162 |
+
# we could allow changing just node arg, so that we end up with bar=baz.
|
| 163 |
+
raise ValueError(
|
| 164 |
+
'a keyword argument may only be replaced by another keyword or a '
|
| 165 |
+
'non-empty list of keywords. Found: {} for keyword {}'.format(
|
| 166 |
+
repl, node.arg))
|
| 167 |
+
|
| 168 |
+
def visit_FunctionDef(self, node):
|
| 169 |
+
node = self.generic_visit(node)
|
| 170 |
+
if node.name not in self.replacements:
|
| 171 |
+
return node
|
| 172 |
+
|
| 173 |
+
repl = self.replacements[node.name]
|
| 174 |
+
if not isinstance(repl, (gast.Name, ast.Name)):
|
| 175 |
+
raise ValueError(
|
| 176 |
+
'a function name can only be replaced by a Name node. Found: %s' %
|
| 177 |
+
repl)
|
| 178 |
+
node.name = repl.id
|
| 179 |
+
return node
|
| 180 |
+
|
| 181 |
+
def visit_Attribute(self, node):
|
| 182 |
+
node = self.generic_visit(node)
|
| 183 |
+
if node.attr not in self.replacements:
|
| 184 |
+
return node
|
| 185 |
+
|
| 186 |
+
repl = self.replacements[node.attr]
|
| 187 |
+
if not isinstance(repl, gast.Name):
|
| 188 |
+
raise ValueError(
|
| 189 |
+
'An attribute can only be replaced by a Name node. Found: %s' % repl)
|
| 190 |
+
node.attr = repl.id
|
| 191 |
+
return node
|
| 192 |
+
|
| 193 |
+
def visit_Name(self, node):
|
| 194 |
+
if node.id not in self.replacements:
|
| 195 |
+
return node
|
| 196 |
+
|
| 197 |
+
new_nodes = self._prepare_replacement(node, node.id)
|
| 198 |
+
|
| 199 |
+
if not new_nodes:
|
| 200 |
+
return new_nodes
|
| 201 |
+
|
| 202 |
+
# Preserve the target context.
|
| 203 |
+
adjuster = ContextAdjuster(type(node.ctx))
|
| 204 |
+
for n in new_nodes:
|
| 205 |
+
if hasattr(n, 'ctx'):
|
| 206 |
+
adjuster.visit(n)
|
| 207 |
+
|
| 208 |
+
if len(new_nodes) == 1:
|
| 209 |
+
new_nodes, = new_nodes
|
| 210 |
+
|
| 211 |
+
return new_nodes
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def _convert_to_ast(n):
|
| 215 |
+
"""Converts from a known data type to AST."""
|
| 216 |
+
# Note: When generating AST nodes from strings/QNs in isolation, ctx is
|
| 217 |
+
# unknown. ctx must be filled in according to the template being used.
|
| 218 |
+
# See ReplaceTransformer.visit_Name.
|
| 219 |
+
if isinstance(n, str):
|
| 220 |
+
return gast.Name(id=n, ctx=None, annotation=None, type_comment=None)
|
| 221 |
+
if isinstance(n, qual_names.QN):
|
| 222 |
+
return n.ast()
|
| 223 |
+
if isinstance(n, list):
|
| 224 |
+
return [_convert_to_ast(e) for e in n]
|
| 225 |
+
if isinstance(n, tuple):
|
| 226 |
+
return tuple(_convert_to_ast(e) for e in n)
|
| 227 |
+
return n
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
def replace(template, **replacements):
|
| 231 |
+
"""Replaces placeholders in a Python template.
|
| 232 |
+
|
| 233 |
+
AST Name and Tuple nodes always receive the context that inferred from
|
| 234 |
+
the template. However, when replacing more complex nodes (that can potentially
|
| 235 |
+
contain Name children), then the caller is responsible for setting the
|
| 236 |
+
appropriate context.
|
| 237 |
+
|
| 238 |
+
Args:
|
| 239 |
+
template: A string representing Python code. Any symbol name can be used
|
| 240 |
+
that appears in the template code can be used as placeholder.
|
| 241 |
+
**replacements: A mapping from placeholder names to (lists of) AST nodes
|
| 242 |
+
that these placeholders will be replaced by. String values are also
|
| 243 |
+
supported as a shorthand for AST Name nodes with the respective ID.
|
| 244 |
+
|
| 245 |
+
Returns:
|
| 246 |
+
An AST node or list of AST nodes with the replacements made. If the
|
| 247 |
+
template was a function, a list will be returned. If the template was a
|
| 248 |
+
node, the same node will be returned. If the template was a string, an
|
| 249 |
+
AST node will be returned (a `Module` node in the case of a multi-line
|
| 250 |
+
string, an `Expr` node otherwise).
|
| 251 |
+
|
| 252 |
+
Raises:
|
| 253 |
+
ValueError: if the arguments are incorrect.
|
| 254 |
+
"""
|
| 255 |
+
if not isinstance(template, str):
|
| 256 |
+
raise ValueError('Expected string template, got %s' % type(template))
|
| 257 |
+
for k in replacements:
|
| 258 |
+
replacements[k] = _convert_to_ast(replacements[k])
|
| 259 |
+
template_str = parser.STANDARD_PREAMBLE + textwrap.dedent(template)
|
| 260 |
+
nodes = parser.parse(
|
| 261 |
+
template_str,
|
| 262 |
+
preamble_len=parser.STANDARD_PREAMBLE_LEN,
|
| 263 |
+
single_node=False)
|
| 264 |
+
results = []
|
| 265 |
+
for node in nodes:
|
| 266 |
+
node = ReplaceTransformer(replacements).visit(node)
|
| 267 |
+
if isinstance(node, (list, tuple)):
|
| 268 |
+
results.extend(node)
|
| 269 |
+
else:
|
| 270 |
+
results.append(node)
|
| 271 |
+
results = [qual_names.resolve(r) for r in results]
|
| 272 |
+
return results
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
def replace_as_expression(template, **replacements):
|
| 276 |
+
"""Variant of replace that generates expressions, instead of code blocks."""
|
| 277 |
+
replacement = replace(template, **replacements)
|
| 278 |
+
if len(replacement) != 1:
|
| 279 |
+
raise ValueError(
|
| 280 |
+
'single expression expected; for more general templates use replace')
|
| 281 |
+
node, = replacement
|
| 282 |
+
|
| 283 |
+
if isinstance(node, gast.Expr):
|
| 284 |
+
return node.value
|
| 285 |
+
elif isinstance(node, gast.Name):
|
| 286 |
+
return node
|
| 287 |
+
|
| 288 |
+
raise ValueError(
|
| 289 |
+
'the template is expected to generate an expression or a name node;'
|
| 290 |
+
' instead found %s' % node)
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/transformer.py
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""A node transformer that includes utilities for SCT."""
|
| 16 |
+
|
| 17 |
+
import collections
|
| 18 |
+
import enum
|
| 19 |
+
|
| 20 |
+
import gast
|
| 21 |
+
|
| 22 |
+
from tensorflow.python.autograph.pyct import anno
|
| 23 |
+
from tensorflow.python.autograph.pyct import parser
|
| 24 |
+
from tensorflow.python.autograph.pyct import pretty_printer
|
| 25 |
+
from tensorflow.python.autograph.pyct import templates
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class AnalysisLevel(enum.IntEnum):
|
| 29 |
+
|
| 30 |
+
NONE = 0
|
| 31 |
+
ACTIVITY = 1
|
| 32 |
+
DEFINEDNESS = 2
|
| 33 |
+
LIVENESS = 3
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
# TODO(znado): Use namedtuple.
|
| 37 |
+
class Context(object):
|
| 38 |
+
"""Contains information about a source code transformation.
|
| 39 |
+
|
| 40 |
+
This object is mutable, and is updated during conversion. Not thread safe.
|
| 41 |
+
|
| 42 |
+
Attributes:
|
| 43 |
+
info: EntityInfo, immutable.
|
| 44 |
+
namer: naming.Namer.
|
| 45 |
+
current_origin: origin_info.OriginInfo, holds the OriginInfo of the last
|
| 46 |
+
AST node to be processed successfully. Useful for error handling.
|
| 47 |
+
user: An user-supplied context object. The object is opaque to the
|
| 48 |
+
infrastructure, but will pe passed through to all custom transformations.
|
| 49 |
+
"""
|
| 50 |
+
|
| 51 |
+
def __init__(self, info, namer, user_context):
|
| 52 |
+
self.info = info
|
| 53 |
+
self.namer = namer
|
| 54 |
+
self.current_origin = None
|
| 55 |
+
self.user = user_context
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
# TODO(mdan): Move to a standalone file.
|
| 59 |
+
class EntityInfo(
|
| 60 |
+
collections.namedtuple(
|
| 61 |
+
'EntityInfo',
|
| 62 |
+
('name', 'source_code', 'source_file', 'future_features', 'namespace'))
|
| 63 |
+
):
|
| 64 |
+
"""Contains information about a Python entity.
|
| 65 |
+
|
| 66 |
+
Immutable.
|
| 67 |
+
|
| 68 |
+
Examples of entities include functions and classes.
|
| 69 |
+
|
| 70 |
+
Attributes:
|
| 71 |
+
name: The name that identifies this entity.
|
| 72 |
+
source_code: The entity's source code.
|
| 73 |
+
source_file: The entity's source file.
|
| 74 |
+
future_features: Tuple[Text], the future features that this entity was
|
| 75 |
+
compiled with. See
|
| 76 |
+
https://docs.python.org/2/reference/simple_stmts.html#future.
|
| 77 |
+
namespace: Dict[str, ], containing symbols visible to the entity (excluding
|
| 78 |
+
parameters).
|
| 79 |
+
"""
|
| 80 |
+
pass
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
class _StateStack(object):
|
| 84 |
+
"""Templated context manager.
|
| 85 |
+
|
| 86 |
+
This class provides syntactic sugar for a stack of objects of known
|
| 87 |
+
type. It allows accessing attributes of the object at the top of the stack
|
| 88 |
+
directly against this object, which allows for very terse syntax.
|
| 89 |
+
|
| 90 |
+
For example, this code:
|
| 91 |
+
|
| 92 |
+
stack = _StateStack(Foo)
|
| 93 |
+
stack.enter()
|
| 94 |
+
stack.bar
|
| 95 |
+
|
| 96 |
+
Is equivalent to:
|
| 97 |
+
|
| 98 |
+
stack = []
|
| 99 |
+
stack.append(Foo())
|
| 100 |
+
foo = stack[-1]
|
| 101 |
+
foo.bar
|
| 102 |
+
|
| 103 |
+
See _State for more on how this is used.
|
| 104 |
+
|
| 105 |
+
Attributes:
|
| 106 |
+
type: Any, the type of objects that this stack holds
|
| 107 |
+
level: int, the current stack depth
|
| 108 |
+
stack: List[Any], the actual stack
|
| 109 |
+
value: Any, the instance of the object at the top of the stack
|
| 110 |
+
"""
|
| 111 |
+
|
| 112 |
+
def __init__(self, type_):
|
| 113 |
+
# Because we override __setattr__, we need to attach these attributes using
|
| 114 |
+
# the superclass' setattr.
|
| 115 |
+
object.__setattr__(self, 'type', type_)
|
| 116 |
+
object.__setattr__(self, '_stack', [])
|
| 117 |
+
if not hasattr(type_, 'no_root'):
|
| 118 |
+
self.enter()
|
| 119 |
+
|
| 120 |
+
def __enter__(self):
|
| 121 |
+
self.enter()
|
| 122 |
+
return self
|
| 123 |
+
|
| 124 |
+
def __exit__(self, exc_type, exc_value, traceback):
|
| 125 |
+
self.exit()
|
| 126 |
+
|
| 127 |
+
def enter(self):
|
| 128 |
+
self._stack.append(self.type())
|
| 129 |
+
|
| 130 |
+
def exit(self):
|
| 131 |
+
self._stack.pop()
|
| 132 |
+
|
| 133 |
+
@property
|
| 134 |
+
def stack(self):
|
| 135 |
+
return self._stack
|
| 136 |
+
|
| 137 |
+
@property
|
| 138 |
+
def level(self):
|
| 139 |
+
return len(self._stack)
|
| 140 |
+
|
| 141 |
+
@property
|
| 142 |
+
def value(self):
|
| 143 |
+
return self._stack[-1]
|
| 144 |
+
|
| 145 |
+
def __iter__(self):
|
| 146 |
+
return iter(self._stack)
|
| 147 |
+
|
| 148 |
+
def __getattr__(self, key):
|
| 149 |
+
return getattr(self._stack[-1], key)
|
| 150 |
+
|
| 151 |
+
def __setattr__(self, key, value):
|
| 152 |
+
setattr(self._stack[-1], key, value)
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
class _State(object):
|
| 156 |
+
"""Syntactic sugar for accessing an instance of a StateStack context manager.
|
| 157 |
+
|
| 158 |
+
This structure offers syntactic sugar over a dict of stacks of objects
|
| 159 |
+
of known type. These structures are useful to keep state during AST walks.
|
| 160 |
+
Multiple different scopes can be tracked in parallel. For example:
|
| 161 |
+
|
| 162 |
+
s = _State()
|
| 163 |
+
|
| 164 |
+
s[foo].enter()
|
| 165 |
+
s[bar].enter() # this will not affect s[foo]
|
| 166 |
+
|
| 167 |
+
Element access has special semantics:
|
| 168 |
+
* keys are a data type
|
| 169 |
+
* element values are _StateStack(type=key) objects
|
| 170 |
+
* missing elements are automatically added, similarly to defaultdict
|
| 171 |
+
|
| 172 |
+
For example, the following block :
|
| 173 |
+
|
| 174 |
+
_State s
|
| 175 |
+
s[Foo]
|
| 176 |
+
|
| 177 |
+
Is equivalent to:
|
| 178 |
+
|
| 179 |
+
s = {}
|
| 180 |
+
if Foo not in s:
|
| 181 |
+
s[Foo] = Foo()
|
| 182 |
+
s[Foo]
|
| 183 |
+
|
| 184 |
+
See Base for how it's used.
|
| 185 |
+
"""
|
| 186 |
+
|
| 187 |
+
def __init__(self):
|
| 188 |
+
self._value = {}
|
| 189 |
+
|
| 190 |
+
def __getitem__(self, key):
|
| 191 |
+
if key not in self._value:
|
| 192 |
+
self._value[key] = _StateStack(key)
|
| 193 |
+
return self._value[key]
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
class NodeStateTracker(object):
|
| 197 |
+
"""Base class for general-purpose Python code transformation.
|
| 198 |
+
|
| 199 |
+
This abstract class provides helpful functions, like state tracking within
|
| 200 |
+
the scope of arbitrary node, helpers for processing code blocks, debugging,
|
| 201 |
+
mapping of transformed code to original code, and others.
|
| 202 |
+
|
| 203 |
+
Scope-local state tracking: to keep state across nodes, at the level of
|
| 204 |
+
(possibly nested) scopes, use enter/exit_local_scope and set/get_local.
|
| 205 |
+
You must call enter/exit_local_scope manually, but the transformer detects
|
| 206 |
+
when they are not properly paired.
|
| 207 |
+
|
| 208 |
+
The transformer allows keeping state across calls that is local
|
| 209 |
+
to arbitrary nodes and their descendants, using the self.state attribute.
|
| 210 |
+
Multiple independent scopes are allowed and automatically constructed.
|
| 211 |
+
|
| 212 |
+
For example, to keep track of the `If` node that encloses any `Name` node,
|
| 213 |
+
one can write:
|
| 214 |
+
|
| 215 |
+
```
|
| 216 |
+
class FooType(object):
|
| 217 |
+
|
| 218 |
+
def __init__(self):
|
| 219 |
+
self.foo_property = None
|
| 220 |
+
|
| 221 |
+
class DummyTransformer(NodeStateTracker, ast.NodeTransformer):
|
| 222 |
+
|
| 223 |
+
def visit_If(self, node):
|
| 224 |
+
self.state[FooType].enter()
|
| 225 |
+
self.state[FooType].foo_property = node
|
| 226 |
+
node = self.veneric_visit(node)
|
| 227 |
+
self.state[FooType].exit()
|
| 228 |
+
return node
|
| 229 |
+
|
| 230 |
+
def visit_Name(self, node):
|
| 231 |
+
self.state[FooType].foo_property # will hold the innermost enclosing if
|
| 232 |
+
```
|
| 233 |
+
|
| 234 |
+
Alternatively, the `enter()`/`exit()` calls can be managed by a `with`
|
| 235 |
+
statement:
|
| 236 |
+
|
| 237 |
+
```
|
| 238 |
+
def visit_If(self, node):
|
| 239 |
+
with self.state[FooType] as foo:
|
| 240 |
+
foo.foo_property = node
|
| 241 |
+
return self.generic_visit(node)
|
| 242 |
+
```
|
| 243 |
+
"""
|
| 244 |
+
|
| 245 |
+
# TODO(mdan): Document all extra features.
|
| 246 |
+
|
| 247 |
+
def __init__(self, ctx):
|
| 248 |
+
"""Initialize the transformer.
|
| 249 |
+
|
| 250 |
+
Subclasses should call this.
|
| 251 |
+
|
| 252 |
+
Args:
|
| 253 |
+
ctx: A Context object.
|
| 254 |
+
"""
|
| 255 |
+
self._lineno = 0
|
| 256 |
+
self._col_offset = 0
|
| 257 |
+
self.ctx = ctx
|
| 258 |
+
|
| 259 |
+
# Allows scoping of local variables to keep state across calls to visit_*
|
| 260 |
+
# methods. Multiple scope hierarchies may exist and are keyed by tag. A
|
| 261 |
+
# scope is valid at one or more nodes and all its children. Scopes created
|
| 262 |
+
# in child nodes supersede their parent. Scopes are isolated from one
|
| 263 |
+
# another.
|
| 264 |
+
self.state = _State()
|
| 265 |
+
|
| 266 |
+
def debug_print(self, node):
|
| 267 |
+
"""Helper method useful for debugging. Prints the AST."""
|
| 268 |
+
if __debug__:
|
| 269 |
+
print(pretty_printer.fmt(node))
|
| 270 |
+
return node
|
| 271 |
+
|
| 272 |
+
def debug_print_src(self, node):
|
| 273 |
+
"""Helper method useful for debugging. Prints the AST as code."""
|
| 274 |
+
if __debug__:
|
| 275 |
+
print(parser.unparse(node))
|
| 276 |
+
return node
|
| 277 |
+
|
| 278 |
+
def visit_block(self, nodes, before_visit=None, after_visit=None):
|
| 279 |
+
"""A more powerful version of generic_visit for statement blocks.
|
| 280 |
+
|
| 281 |
+
An example of a block is the body of an if statement.
|
| 282 |
+
|
| 283 |
+
This function allows specifying a postprocessing callback (the
|
| 284 |
+
after_visit argument) argument which can be used to move nodes to a new
|
| 285 |
+
destination. This is done by after_visit by returning a non-null
|
| 286 |
+
second return value, e.g. return new_node, new_destination.
|
| 287 |
+
|
| 288 |
+
For example, a transformer could perform the following move:
|
| 289 |
+
|
| 290 |
+
foo()
|
| 291 |
+
bar()
|
| 292 |
+
baz()
|
| 293 |
+
|
| 294 |
+
foo()
|
| 295 |
+
if cond:
|
| 296 |
+
bar()
|
| 297 |
+
baz()
|
| 298 |
+
|
| 299 |
+
The above could be done with a postprocessor of this kind:
|
| 300 |
+
|
| 301 |
+
def after_visit(node):
|
| 302 |
+
if node_is_function_call(bar):
|
| 303 |
+
new_container_node = build_cond()
|
| 304 |
+
new_container_node.body.append(node)
|
| 305 |
+
return new_container_node, new_container_node.body
|
| 306 |
+
else:
|
| 307 |
+
# Once we set a new destination, all subsequent items will be
|
| 308 |
+
# moved to it, so we don't need to explicitly handle baz.
|
| 309 |
+
return node, None
|
| 310 |
+
|
| 311 |
+
Args:
|
| 312 |
+
nodes: enumerable of AST node objects. If None, the function returns None.
|
| 313 |
+
before_visit: optional callable that is called before visiting each item
|
| 314 |
+
in nodes
|
| 315 |
+
after_visit: optional callable that takes in an AST node and returns a
|
| 316 |
+
tuple (new_node, new_destination). It is called after visiting each item
|
| 317 |
+
in nodes. Is used in the same was as the visit_* methods: new_node will
|
| 318 |
+
replace the node; if not None, new_destination must be a list, and
|
| 319 |
+
subsequent nodes will be placed in this list instead of the list
|
| 320 |
+
returned by visit_block.
|
| 321 |
+
|
| 322 |
+
Returns:
|
| 323 |
+
A list of AST node objects containing the transformed items from nodes,
|
| 324 |
+
except those nodes that have been relocated using after_visit.
|
| 325 |
+
"""
|
| 326 |
+
if nodes is None:
|
| 327 |
+
return None
|
| 328 |
+
|
| 329 |
+
results = []
|
| 330 |
+
node_destination = results
|
| 331 |
+
for node in nodes:
|
| 332 |
+
if before_visit:
|
| 333 |
+
# TODO(mdan): We can modify node here too, if ever needed.
|
| 334 |
+
before_visit()
|
| 335 |
+
|
| 336 |
+
replacement = self.visit(node)
|
| 337 |
+
|
| 338 |
+
if after_visit and replacement:
|
| 339 |
+
replacement, new_destination = after_visit(replacement)
|
| 340 |
+
else:
|
| 341 |
+
new_destination = None
|
| 342 |
+
|
| 343 |
+
if replacement:
|
| 344 |
+
if isinstance(replacement, (list, tuple)):
|
| 345 |
+
node_destination.extend(replacement)
|
| 346 |
+
else:
|
| 347 |
+
node_destination.append(replacement)
|
| 348 |
+
|
| 349 |
+
# Allow the postprocessor to reroute the remaining nodes to a new list.
|
| 350 |
+
if new_destination is not None:
|
| 351 |
+
node_destination = new_destination
|
| 352 |
+
return results
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
# TODO(mdan): Rename to PythonCodeTransformer.
|
| 356 |
+
class Base(NodeStateTracker, gast.NodeTransformer):
|
| 357 |
+
"""Base class for general-purpose Python-to-Python code transformation.
|
| 358 |
+
|
| 359 |
+
This is an extension of ast.NodeTransformer that provides the additional
|
| 360 |
+
functions offered by NodeStateTracker.
|
| 361 |
+
"""
|
| 362 |
+
|
| 363 |
+
def create_assignment(self, target, expression):
|
| 364 |
+
template = """
|
| 365 |
+
target = expression
|
| 366 |
+
"""
|
| 367 |
+
return templates.replace(template, target=target, expression=expression)
|
| 368 |
+
|
| 369 |
+
# TODO(mdan): Remove.
|
| 370 |
+
def apply_to_single_assignments(self, targets, values, apply_fn):
|
| 371 |
+
"""Applies a function to each individual assignment.
|
| 372 |
+
|
| 373 |
+
This function can process a possibly-unpacked (e.g. a, b = c, d) assignment.
|
| 374 |
+
It tries to break down the unpacking if possible. In effect, it has the same
|
| 375 |
+
effect as passing the assigned values in SSA form to apply_fn.
|
| 376 |
+
|
| 377 |
+
Examples:
|
| 378 |
+
|
| 379 |
+
The following will result in apply_fn(a, c), apply_fn(b, d):
|
| 380 |
+
|
| 381 |
+
a, b = c, d
|
| 382 |
+
|
| 383 |
+
The following will result in apply_fn(a, c[0]), apply_fn(b, c[1]):
|
| 384 |
+
|
| 385 |
+
a, b = c
|
| 386 |
+
|
| 387 |
+
The following will result in apply_fn(a, (b, c)):
|
| 388 |
+
|
| 389 |
+
a = b, c
|
| 390 |
+
|
| 391 |
+
It uses the visitor pattern to allow subclasses to process single
|
| 392 |
+
assignments individually.
|
| 393 |
+
|
| 394 |
+
Args:
|
| 395 |
+
targets: list, tuple of or individual AST node. Should be used with the
|
| 396 |
+
targets field of an ast.Assign node.
|
| 397 |
+
values: an AST node.
|
| 398 |
+
apply_fn: a function of a single argument, which will be called with the
|
| 399 |
+
respective nodes of each single assignment. The signature is
|
| 400 |
+
apply_fn(target, value), no return value.
|
| 401 |
+
"""
|
| 402 |
+
if not isinstance(targets, (list, tuple)):
|
| 403 |
+
targets = (targets,)
|
| 404 |
+
for target in targets:
|
| 405 |
+
if isinstance(target, (gast.Tuple, gast.List)):
|
| 406 |
+
for i in range(len(target.elts)):
|
| 407 |
+
target_el = target.elts[i]
|
| 408 |
+
if isinstance(values, (gast.Tuple, gast.List)):
|
| 409 |
+
value_el = values.elts[i]
|
| 410 |
+
else:
|
| 411 |
+
value_el = gast.Subscript(values, i, ctx=gast.Store())
|
| 412 |
+
self.apply_to_single_assignments(target_el, value_el, apply_fn)
|
| 413 |
+
else:
|
| 414 |
+
# TODO(mdan): Look into allowing to rewrite the AST here.
|
| 415 |
+
apply_fn(target, values)
|
| 416 |
+
|
| 417 |
+
def visit(self, node):
|
| 418 |
+
if not isinstance(node, gast.AST):
|
| 419 |
+
# This is not that uncommon a mistake: various node bodies are lists, for
|
| 420 |
+
# example, posing a land mine for transformers that need to recursively
|
| 421 |
+
# call `visit`. The error needs to be raised before the exception handler
|
| 422 |
+
# below is installed, because said handler will mess up if `node` is not,
|
| 423 |
+
# in fact, a node.
|
| 424 |
+
msg = ('invalid value for "node": expected "ast.AST", got "{}"; to'
|
| 425 |
+
' visit lists of nodes, use "visit_block" instead').format(
|
| 426 |
+
type(node))
|
| 427 |
+
raise ValueError(msg)
|
| 428 |
+
|
| 429 |
+
if anno.hasanno(node, anno.Basic.SKIP_PROCESSING):
|
| 430 |
+
return node
|
| 431 |
+
|
| 432 |
+
parent_origin = self.ctx.current_origin
|
| 433 |
+
if anno.hasanno(node, anno.Basic.ORIGIN):
|
| 434 |
+
self.ctx.current_origin = anno.getanno(node, anno.Basic.ORIGIN)
|
| 435 |
+
|
| 436 |
+
try:
|
| 437 |
+
processing_expr_node = isinstance(node, gast.Expr)
|
| 438 |
+
if processing_expr_node:
|
| 439 |
+
entry_expr_value = node.value
|
| 440 |
+
|
| 441 |
+
result = super(Base, self).visit(node)
|
| 442 |
+
|
| 443 |
+
# Adjust for consistency: replacing the value of an Expr with
|
| 444 |
+
# an Assign node removes the need for the Expr node.
|
| 445 |
+
if (processing_expr_node and isinstance(result, gast.Expr) and
|
| 446 |
+
(result.value is not entry_expr_value)):
|
| 447 |
+
# When the replacement is a list, it is assumed that the list came
|
| 448 |
+
# from a template that contained a number of statements, which
|
| 449 |
+
# themselves are standalone and don't require an enclosing Expr.
|
| 450 |
+
if isinstance(result.value,
|
| 451 |
+
(list, tuple, gast.Assign, gast.AugAssign)):
|
| 452 |
+
result = result.value
|
| 453 |
+
|
| 454 |
+
# By default, all replacements receive the origin info of the replaced
|
| 455 |
+
# node.
|
| 456 |
+
if result is not node and result is not None:
|
| 457 |
+
inherited_origin = anno.getanno(
|
| 458 |
+
node, anno.Basic.ORIGIN, default=parent_origin)
|
| 459 |
+
if inherited_origin is not None:
|
| 460 |
+
nodes_to_adjust = result
|
| 461 |
+
if isinstance(result, (list, tuple)):
|
| 462 |
+
nodes_to_adjust = result
|
| 463 |
+
else:
|
| 464 |
+
nodes_to_adjust = (result,)
|
| 465 |
+
for n in nodes_to_adjust:
|
| 466 |
+
if not anno.hasanno(n, anno.Basic.ORIGIN):
|
| 467 |
+
anno.setanno(n, anno.Basic.ORIGIN, inherited_origin)
|
| 468 |
+
finally:
|
| 469 |
+
self.ctx.current_origin = parent_origin
|
| 470 |
+
|
| 471 |
+
return result
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
class CodeGenerator(NodeStateTracker, gast.NodeVisitor):
|
| 475 |
+
"""Base class for general-purpose Python-to-string code transformation.
|
| 476 |
+
|
| 477 |
+
Similar to Base, but outputs arbitrary strings instead of a Python AST.
|
| 478 |
+
|
| 479 |
+
This uses the same visitor mechanism that the standard NodeVisitor uses,
|
| 480 |
+
meaning that subclasses write handlers for the different kinds of nodes.
|
| 481 |
+
New code is generated using the emit method, which appends to a code buffer
|
| 482 |
+
that can be afterwards obtained from code_buffer.
|
| 483 |
+
|
| 484 |
+
Example:
|
| 485 |
+
|
| 486 |
+
class SimpleCodeGen(CodeGenerator):
|
| 487 |
+
|
| 488 |
+
def visitIf(self, node):
|
| 489 |
+
self.emit('if ')
|
| 490 |
+
self.visit(node.test)
|
| 491 |
+
self.emit(' { ')
|
| 492 |
+
self.visit(node.body)
|
| 493 |
+
self.emit(' } else { ')
|
| 494 |
+
self.visit(node.orelse)
|
| 495 |
+
self.emit(' } ')
|
| 496 |
+
|
| 497 |
+
node = ast.parse(...)
|
| 498 |
+
gen = SimpleCodeGen()
|
| 499 |
+
gen.visit(node)
|
| 500 |
+
# gen.code_buffer contains the resulting code
|
| 501 |
+
"""
|
| 502 |
+
|
| 503 |
+
def __init__(self, ctx):
|
| 504 |
+
super(CodeGenerator, self).__init__(ctx)
|
| 505 |
+
|
| 506 |
+
self._output_code = ''
|
| 507 |
+
self.source_map = {}
|
| 508 |
+
|
| 509 |
+
def emit(self, code):
|
| 510 |
+
self._output_code += code
|
| 511 |
+
|
| 512 |
+
@property
|
| 513 |
+
def code_buffer(self):
|
| 514 |
+
return self._output_code
|
| 515 |
+
|
| 516 |
+
def visit(self, node):
|
| 517 |
+
if anno.hasanno(node, anno.Basic.SKIP_PROCESSING):
|
| 518 |
+
return
|
| 519 |
+
|
| 520 |
+
parent_origin = self.ctx.current_origin
|
| 521 |
+
eof_before = len(self._output_code)
|
| 522 |
+
if anno.hasanno(node, anno.Basic.ORIGIN):
|
| 523 |
+
self.ctx.current_origin = anno.getanno(node, anno.Basic.ORIGIN)
|
| 524 |
+
|
| 525 |
+
try:
|
| 526 |
+
ret = super(CodeGenerator, self).visit(node)
|
| 527 |
+
|
| 528 |
+
# By default, all replacements receive the origin info of the replaced
|
| 529 |
+
# node.
|
| 530 |
+
eof_after = len(self._output_code)
|
| 531 |
+
if eof_before - eof_after:
|
| 532 |
+
inherited_origin = anno.getanno(
|
| 533 |
+
node, anno.Basic.ORIGIN, default=parent_origin)
|
| 534 |
+
if inherited_origin is not None:
|
| 535 |
+
self.source_map[(eof_before, eof_after)] = inherited_origin
|
| 536 |
+
return ret
|
| 537 |
+
finally:
|
| 538 |
+
self.ctx.current_origin = parent_origin
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/autograph/pyct/transpiler.py
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# ==============================================================================
|
| 15 |
+
"""Generic source code transformation infrastructure."""
|
| 16 |
+
|
| 17 |
+
import inspect
|
| 18 |
+
import threading
|
| 19 |
+
import types
|
| 20 |
+
|
| 21 |
+
import gast
|
| 22 |
+
|
| 23 |
+
from tensorflow.python.autograph.pyct import cache
|
| 24 |
+
from tensorflow.python.autograph.pyct import inspect_utils
|
| 25 |
+
from tensorflow.python.autograph.pyct import loader
|
| 26 |
+
from tensorflow.python.autograph.pyct import naming
|
| 27 |
+
from tensorflow.python.autograph.pyct import origin_info
|
| 28 |
+
from tensorflow.python.autograph.pyct import parser
|
| 29 |
+
from tensorflow.python.autograph.pyct import templates
|
| 30 |
+
from tensorflow.python.autograph.pyct import transformer
|
| 31 |
+
from tensorflow.python.autograph.utils import ag_logging as logging
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def _wrap_into_factory(nodes, entity_name, inner_factory_name,
|
| 35 |
+
outer_factory_name, closure_vars, factory_args,
|
| 36 |
+
future_features):
|
| 37 |
+
"""Wraps an AST into the body of a factory with consistent lexical context.
|
| 38 |
+
|
| 39 |
+
The AST is expected to define some symbol with a name given by `entity_name`.
|
| 40 |
+
|
| 41 |
+
This mechanism ensures that the resulting transformed entity has lexical
|
| 42 |
+
scoping identical to that of the source entity, while allowing extra
|
| 43 |
+
parametrization.
|
| 44 |
+
|
| 45 |
+
Two nested factories achieve the following:
|
| 46 |
+
|
| 47 |
+
1. The inner factory dynamically creates the entity represented by `nodes`.
|
| 48 |
+
2. The inner factory is parametrized by a custom set of arguments.
|
| 49 |
+
3. The inner factory has a closure identical to that of the transformed
|
| 50 |
+
entity.
|
| 51 |
+
4. The inner factory has local variables named like `args`, which `nodes` may
|
| 52 |
+
use as additional parameters.
|
| 53 |
+
5. The inner factory returns the variables given by `entity_name`.
|
| 54 |
+
6. The outer factory is niladic.
|
| 55 |
+
7. The outer factory has no closure.
|
| 56 |
+
8. The outer factory creates the necessary lexical scope for the inner
|
| 57 |
+
factory, so that the loaded code has the given configuration for
|
| 58 |
+
closure/globals.
|
| 59 |
+
9. The outer factory returns the inner factory.
|
| 60 |
+
|
| 61 |
+
Roughly speaking, the following code is generated:
|
| 62 |
+
|
| 63 |
+
from __future__ import future_feature_1
|
| 64 |
+
from __future__ import future_feature_2
|
| 65 |
+
...
|
| 66 |
+
|
| 67 |
+
def outer_factory():
|
| 68 |
+
closure_var_1 = None
|
| 69 |
+
closure_var_2 = None
|
| 70 |
+
...
|
| 71 |
+
|
| 72 |
+
def inner_factory(arg_1, arg_2, ...):
|
| 73 |
+
<<nodes>>
|
| 74 |
+
return entity
|
| 75 |
+
|
| 76 |
+
return inner_factory
|
| 77 |
+
|
| 78 |
+
The lexical scoping is created using dummy symbol declarations which create
|
| 79 |
+
local variables in the body of the outer factory, so that the Python parser
|
| 80 |
+
correctly marks them as free non-global variables upon load (that is, it
|
| 81 |
+
creates cell slots for each symbol. These symbols are initialized with None,
|
| 82 |
+
but their values are not expected to be used; instead, the caller is expected
|
| 83 |
+
to replace them with the cells of the source entity. For more details, see:
|
| 84 |
+
https://docs.python.org/3/reference/executionmodel.html#binding-of-names
|
| 85 |
+
|
| 86 |
+
Args:
|
| 87 |
+
nodes: Tuple[ast.AST], the source code to wrap.
|
| 88 |
+
entity_name: Union[Text, ast.AST], the name of the principal entity that
|
| 89 |
+
`nodes` define.
|
| 90 |
+
inner_factory_name: Text, the name of the inner factory.
|
| 91 |
+
outer_factory_name: Text, the name of the outer factory.
|
| 92 |
+
closure_vars: Iterable[Text], names of the closure variables for the inner
|
| 93 |
+
factory.
|
| 94 |
+
factory_args: Iterable[Text], names of additional arguments for the
|
| 95 |
+
inner factory. Useful to configure variables that the converted code can
|
| 96 |
+
use. Typically, these are modules.
|
| 97 |
+
future_features: Iterable[Text], names of future statements to associate the
|
| 98 |
+
code with.
|
| 99 |
+
|
| 100 |
+
Returns:
|
| 101 |
+
ast.AST
|
| 102 |
+
"""
|
| 103 |
+
dummy_closure_defs = []
|
| 104 |
+
for var_name in closure_vars:
|
| 105 |
+
template = """
|
| 106 |
+
var_name = None
|
| 107 |
+
"""
|
| 108 |
+
dummy_closure_defs.extend(templates.replace(template, var_name=var_name))
|
| 109 |
+
|
| 110 |
+
if future_features:
|
| 111 |
+
future_imports = gast.ImportFrom(
|
| 112 |
+
module='__future__',
|
| 113 |
+
names=[gast.alias(name=name, asname=None) for name in future_features],
|
| 114 |
+
level=0)
|
| 115 |
+
else:
|
| 116 |
+
future_imports = []
|
| 117 |
+
|
| 118 |
+
factory_args = [
|
| 119 |
+
gast.Name(name, ctx=gast.Param(), annotation=None, type_comment=None)
|
| 120 |
+
for name in factory_args
|
| 121 |
+
]
|
| 122 |
+
|
| 123 |
+
template = """
|
| 124 |
+
future_imports
|
| 125 |
+
def outer_factory_name():
|
| 126 |
+
dummy_closure_defs
|
| 127 |
+
def inner_factory_name(factory_args):
|
| 128 |
+
entity_defs
|
| 129 |
+
return entity_name
|
| 130 |
+
return inner_factory_name
|
| 131 |
+
"""
|
| 132 |
+
return templates.replace(
|
| 133 |
+
template,
|
| 134 |
+
dummy_closure_defs=dummy_closure_defs,
|
| 135 |
+
entity_defs=nodes,
|
| 136 |
+
entity_name=entity_name,
|
| 137 |
+
factory_args=factory_args,
|
| 138 |
+
future_imports=future_imports,
|
| 139 |
+
inner_factory_name=inner_factory_name,
|
| 140 |
+
outer_factory_name=outer_factory_name)
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
class _PythonFnFactory(object):
|
| 144 |
+
"""Helper object that wraps a Python function factory."""
|
| 145 |
+
|
| 146 |
+
def __init__(self, name, freevars, extra_locals):
|
| 147 |
+
"""Creates a new factory for a Python function.
|
| 148 |
+
|
| 149 |
+
Args:
|
| 150 |
+
name: The function name.
|
| 151 |
+
freevars: The list of non-global free variables for the function.
|
| 152 |
+
extra_locals: Dict[Text, Any], names and values for custom variables that
|
| 153 |
+
are accessible to the generated code as local variables.
|
| 154 |
+
"""
|
| 155 |
+
self._name = name
|
| 156 |
+
self._freevars = freevars
|
| 157 |
+
self._extra_locals = extra_locals
|
| 158 |
+
|
| 159 |
+
self._unbound_factory = None
|
| 160 |
+
self.module = None
|
| 161 |
+
self.source_map = None
|
| 162 |
+
|
| 163 |
+
def create(self,
|
| 164 |
+
nodes,
|
| 165 |
+
namer,
|
| 166 |
+
inner_factory_name='inner_factory',
|
| 167 |
+
outer_factory_name='outer_factory',
|
| 168 |
+
future_features=()):
|
| 169 |
+
"""Initializes a function."""
|
| 170 |
+
if self._unbound_factory is not None:
|
| 171 |
+
raise ValueError('double initialization; create a new object instead')
|
| 172 |
+
|
| 173 |
+
inner_factory_name = namer.new_symbol(inner_factory_name, ())
|
| 174 |
+
outer_factory_name = namer.new_symbol(outer_factory_name, ())
|
| 175 |
+
nodes = _wrap_into_factory(nodes, self._name, inner_factory_name,
|
| 176 |
+
outer_factory_name, self._freevars,
|
| 177 |
+
self._extra_locals.keys(), future_features)
|
| 178 |
+
|
| 179 |
+
module, _, source_map = loader.load_ast(
|
| 180 |
+
nodes, include_source_map=True)
|
| 181 |
+
outer_factory = getattr(module, outer_factory_name)
|
| 182 |
+
self._unbound_factory = outer_factory()
|
| 183 |
+
self.module = module
|
| 184 |
+
self.source_map = source_map
|
| 185 |
+
|
| 186 |
+
def instantiate(self,
|
| 187 |
+
globals_,
|
| 188 |
+
closure,
|
| 189 |
+
defaults=None,
|
| 190 |
+
kwdefaults=None):
|
| 191 |
+
"""Creates a new function instance."""
|
| 192 |
+
if self._unbound_factory is None:
|
| 193 |
+
raise ValueError('call create first')
|
| 194 |
+
|
| 195 |
+
factory_code = self._unbound_factory.__code__
|
| 196 |
+
factory_freevars = factory_code.co_freevars
|
| 197 |
+
closure_map = dict(zip(self._freevars, closure))
|
| 198 |
+
factory_closure = tuple(
|
| 199 |
+
closure_map[name] for name in factory_code.co_freevars)
|
| 200 |
+
if len(factory_closure) != len(closure):
|
| 201 |
+
raise ValueError(
|
| 202 |
+
'closure mismatch, requested {}, but source function had {}'.format(
|
| 203 |
+
self._freevars, factory_freevars))
|
| 204 |
+
|
| 205 |
+
bound_factory = types.FunctionType(
|
| 206 |
+
code=factory_code,
|
| 207 |
+
globals=globals_,
|
| 208 |
+
name=self._name,
|
| 209 |
+
argdefs=(),
|
| 210 |
+
closure=factory_closure)
|
| 211 |
+
|
| 212 |
+
# The lint override is a false positive.
|
| 213 |
+
new_fn = bound_factory(**self._extra_locals) # pylint:disable=not-callable
|
| 214 |
+
|
| 215 |
+
if defaults:
|
| 216 |
+
new_fn.__defaults__ = defaults
|
| 217 |
+
if kwdefaults:
|
| 218 |
+
new_fn.__kwdefaults__ = kwdefaults
|
| 219 |
+
|
| 220 |
+
return new_fn
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
class GenericTranspiler(object):
|
| 224 |
+
"""A generic transpiler for Python functions.
|
| 225 |
+
|
| 226 |
+
Its interface is the `transform` API, which can process Python function
|
| 227 |
+
objects. Internally, it handles parsing.
|
| 228 |
+
|
| 229 |
+
Users typically subclass this, customizing the `transform_ast` method. The
|
| 230 |
+
output of transformed_ast is returned directly by `transform`. Existing
|
| 231 |
+
methods like `transform_function` may also be overloaded.
|
| 232 |
+
|
| 233 |
+
Example:
|
| 234 |
+
|
| 235 |
+
class MyTransformer(GenericTranspiler):
|
| 236 |
+
|
| 237 |
+
def transform_ast(self, node, ctx):
|
| 238 |
+
result = <<transform node>>
|
| 239 |
+
return result
|
| 240 |
+
|
| 241 |
+
transformer = MyTransformer()
|
| 242 |
+
|
| 243 |
+
result = transformer.transform(f, ...)
|
| 244 |
+
# result is the output
|
| 245 |
+
"""
|
| 246 |
+
|
| 247 |
+
def get_transformed_name(self, node):
|
| 248 |
+
"""Returns a name for the output function. Subclasses may override this."""
|
| 249 |
+
if isinstance(node, gast.Lambda):
|
| 250 |
+
return 'lam'
|
| 251 |
+
elif isinstance(node, gast.FunctionDef):
|
| 252 |
+
return node.name
|
| 253 |
+
raise ValueError('Unknown node type {}'.format(node))
|
| 254 |
+
|
| 255 |
+
def transform_ast(self, node, ctx):
|
| 256 |
+
"""Performs an actual transformation of a function's AST.
|
| 257 |
+
|
| 258 |
+
Subclasses must implement this method, and do not usually call it.
|
| 259 |
+
|
| 260 |
+
Args:
|
| 261 |
+
node: One or more ast.AST nodes representing the AST to be transformed.
|
| 262 |
+
ctx: transformer.Context.
|
| 263 |
+
"""
|
| 264 |
+
raise NotImplementedError('subclasses must override this')
|
| 265 |
+
|
| 266 |
+
def transform(self, obj, user_context):
|
| 267 |
+
"""Transforms a Python object.
|
| 268 |
+
|
| 269 |
+
Users typically call this method.
|
| 270 |
+
|
| 271 |
+
Args:
|
| 272 |
+
obj: A Python object, function, type, etc.
|
| 273 |
+
user_context: An opaque object (may be None) that is forwarded to
|
| 274 |
+
transform_ast, through the ctx.user attribute.
|
| 275 |
+
Returns:
|
| 276 |
+
The result of calling transform_function.
|
| 277 |
+
|
| 278 |
+
Raises:
|
| 279 |
+
NotImplementedError: if the type of obj is not handled.
|
| 280 |
+
"""
|
| 281 |
+
if inspect.isfunction(obj) or inspect.ismethod(obj):
|
| 282 |
+
return self.transform_function(obj, user_context)
|
| 283 |
+
|
| 284 |
+
raise NotImplementedError('Non-function: {}'.format(type(obj)))
|
| 285 |
+
|
| 286 |
+
def _erase_arg_defaults(self, node):
|
| 287 |
+
"""Erase arg default expressions, which would otherwise be unbound."""
|
| 288 |
+
args = node.args
|
| 289 |
+
for i in range(len(args.defaults)):
|
| 290 |
+
args.defaults[i] = parser.parse_expression('None')
|
| 291 |
+
for i, d in enumerate(args.kw_defaults):
|
| 292 |
+
if d is not None:
|
| 293 |
+
args.kw_defaults[i] = parser.parse_expression('None')
|
| 294 |
+
return node
|
| 295 |
+
|
| 296 |
+
def transform_module(self, mod, user_context):
|
| 297 |
+
"""Transforms a module.
|
| 298 |
+
|
| 299 |
+
Subclasses may override this method. The return value is opaque.
|
| 300 |
+
|
| 301 |
+
The method receives the original AST. The result is passed as-is to the
|
| 302 |
+
output of `transform`.
|
| 303 |
+
|
| 304 |
+
Args:
|
| 305 |
+
mod: A Python module.
|
| 306 |
+
user_context: An opaque object (may be None) that is forwarded to
|
| 307 |
+
transform_ast, through the ctx.user attribute.
|
| 308 |
+
Returns:
|
| 309 |
+
List[Tuple[Any, Any]]. By default it returns the output of transform_ast,
|
| 310 |
+
evaluated on each supported member, other than modules, together with a
|
| 311 |
+
`transformer.Context` containing information about the transformation
|
| 312 |
+
process.
|
| 313 |
+
"""
|
| 314 |
+
result = []
|
| 315 |
+
for member in mod.__dict__.values():
|
| 316 |
+
if inspect.ismodule(member):
|
| 317 |
+
continue # Not transforming modules recursively.
|
| 318 |
+
try:
|
| 319 |
+
result.append(self.transform(member, user_context))
|
| 320 |
+
except NotImplementedError:
|
| 321 |
+
pass # Skip unsupported elements.
|
| 322 |
+
return result
|
| 323 |
+
|
| 324 |
+
def transform_function(self, fn, user_context):
|
| 325 |
+
"""Transforms a function.
|
| 326 |
+
|
| 327 |
+
Subclasses may override this method. The return value is opaque.
|
| 328 |
+
|
| 329 |
+
The method receives the original AST. The result is passed as-is to the
|
| 330 |
+
output of `transform`.
|
| 331 |
+
|
| 332 |
+
Args:
|
| 333 |
+
fn: A function or lambda.
|
| 334 |
+
user_context: An opaque object (may be None) that is forwarded to
|
| 335 |
+
transform_ast, through the ctx.user attribute.
|
| 336 |
+
Returns:
|
| 337 |
+
Tuple[Any, Any]. By default it returns the output of transform_ast,
|
| 338 |
+
together with a `transformer.Context` containing information about the
|
| 339 |
+
transformation process.
|
| 340 |
+
"""
|
| 341 |
+
future_features = inspect_utils.getfutureimports(fn)
|
| 342 |
+
node, source = parser.parse_entity(fn, future_features=future_features)
|
| 343 |
+
logging.log(3, 'Source code of %s:\n\n%s\n', fn, source)
|
| 344 |
+
|
| 345 |
+
origin_info.resolve_entity(node, source, fn)
|
| 346 |
+
|
| 347 |
+
namespace = inspect_utils.getnamespace(fn)
|
| 348 |
+
namer = naming.Namer(namespace)
|
| 349 |
+
new_name = namer.new_symbol(self.get_transformed_name(node), ())
|
| 350 |
+
entity_info = transformer.EntityInfo(
|
| 351 |
+
name=new_name,
|
| 352 |
+
source_code=source,
|
| 353 |
+
source_file='<fragment>',
|
| 354 |
+
future_features=future_features,
|
| 355 |
+
namespace=namespace)
|
| 356 |
+
context = transformer.Context(entity_info, namer, user_context)
|
| 357 |
+
|
| 358 |
+
node = self._erase_arg_defaults(node)
|
| 359 |
+
result = self.transform_ast(node, context)
|
| 360 |
+
|
| 361 |
+
return result, context
|
| 362 |
+
|
| 363 |
+
|
| 364 |
+
class PyToPy(GenericTranspiler):
|
| 365 |
+
"""A generic Python-to-Python transpiler.
|
| 366 |
+
|
| 367 |
+
Its `transform` method offers a function-in, function-out interface.
|
| 368 |
+
Internally, it takes care of parsing, caching and loading of the translated
|
| 369 |
+
code.
|
| 370 |
+
|
| 371 |
+
Users typically subclass this, overriding `transform_ast`.
|
| 372 |
+
|
| 373 |
+
Usually, instances of this class are singletons, since each instance manages
|
| 374 |
+
its own cache. The caching can be controlled by overriding `get_caching_key`.
|
| 375 |
+
|
| 376 |
+
Example:
|
| 377 |
+
|
| 378 |
+
class MyTransformer(PyToPy):
|
| 379 |
+
|
| 380 |
+
def transform_ast(self, node, ctx):
|
| 381 |
+
node = <<transform node, usually using ast.NodeTransformer classes>>
|
| 382 |
+
return node
|
| 383 |
+
|
| 384 |
+
transformer = MyTransformer()
|
| 385 |
+
|
| 386 |
+
new_f, module, source_map = transformer.transform_function(f, ...)
|
| 387 |
+
# new_f is a function with signature identical to f
|
| 388 |
+
|
| 389 |
+
The transformed function has access to the same namespace as the original
|
| 390 |
+
function. To allow access to internal APIs, users may inject additional
|
| 391 |
+
symbols by overriding `get_extra_locals`.
|
| 392 |
+
"""
|
| 393 |
+
|
| 394 |
+
def __init__(self):
|
| 395 |
+
self._cache_lock = threading.RLock()
|
| 396 |
+
self._cache = cache.CodeObjectCache()
|
| 397 |
+
|
| 398 |
+
def get_extra_locals(self):
|
| 399 |
+
"""Returns extra static local variables to be made to transformed code.
|
| 400 |
+
|
| 401 |
+
Subclasses must override this.
|
| 402 |
+
|
| 403 |
+
Returns:
|
| 404 |
+
extra_locals: A Dict[Text, Any] containing additional variables to make
|
| 405 |
+
available to the transformed code.
|
| 406 |
+
"""
|
| 407 |
+
raise NotImplementedError('subclasses must override this')
|
| 408 |
+
|
| 409 |
+
def get_caching_key(self, user_context):
|
| 410 |
+
"""Returns a unique key to use for caching.
|
| 411 |
+
|
| 412 |
+
Subclasses must override this.
|
| 413 |
+
|
| 414 |
+
Calls made to `transform_function` with functions that have the same code
|
| 415 |
+
object and caching key will return a cached instance on subsequent
|
| 416 |
+
invocations.
|
| 417 |
+
|
| 418 |
+
Args:
|
| 419 |
+
user_context: The context object which was passed to `transform`.
|
| 420 |
+
|
| 421 |
+
Returns:
|
| 422 |
+
extra_locals: A hashable.
|
| 423 |
+
"""
|
| 424 |
+
raise NotImplementedError('subclasses must override this')
|
| 425 |
+
|
| 426 |
+
def _cached_factory(self, fn, cache_subkey):
|
| 427 |
+
cached_factory = self._cache[fn][cache_subkey]
|
| 428 |
+
logging.log(3, 'Cache hit for %s subkey %s: %s', fn, cache_subkey,
|
| 429 |
+
cached_factory)
|
| 430 |
+
return cached_factory
|
| 431 |
+
|
| 432 |
+
def transform_function(self, fn, user_context):
|
| 433 |
+
"""Transforms a function. See GenericTranspiler.transform_function.
|
| 434 |
+
|
| 435 |
+
This overload wraps the parent's `transform_function`, adding caching and
|
| 436 |
+
facilities to instantiate the output as a Python object. It also
|
| 437 |
+
adds facilities to make new symbols available to the generated Python code,
|
| 438 |
+
visible as local variables - see `get_extra_locals`.
|
| 439 |
+
|
| 440 |
+
Args:
|
| 441 |
+
fn: A function or lambda.
|
| 442 |
+
user_context: An opaque object (may be None) that is forwarded to
|
| 443 |
+
transform_ast, through the ctx.user attribute.
|
| 444 |
+
|
| 445 |
+
Returns:
|
| 446 |
+
A tuple:
|
| 447 |
+
* A function or lambda with the same signature and closure as `fn`
|
| 448 |
+
* The temporary module into which the transformed function was loaded
|
| 449 |
+
* The source map as a
|
| 450 |
+
Dict[origin_info.LineLocation, origin_info.OriginInfo]
|
| 451 |
+
"""
|
| 452 |
+
cache_subkey = self.get_caching_key(user_context)
|
| 453 |
+
|
| 454 |
+
if self._cache.has(fn, cache_subkey):
|
| 455 |
+
# Fast path: use a lock-free check.
|
| 456 |
+
factory = self._cached_factory(fn, cache_subkey)
|
| 457 |
+
|
| 458 |
+
else:
|
| 459 |
+
with self._cache_lock:
|
| 460 |
+
# Check again under lock.
|
| 461 |
+
if self._cache.has(fn, cache_subkey):
|
| 462 |
+
factory = self._cached_factory(fn, cache_subkey)
|
| 463 |
+
|
| 464 |
+
else:
|
| 465 |
+
logging.log(1, '%s is not cached for subkey %s', fn, cache_subkey)
|
| 466 |
+
# TODO(mdan): Confusing overloading pattern. Fix.
|
| 467 |
+
nodes, ctx = super(PyToPy, self).transform_function(fn, user_context)
|
| 468 |
+
|
| 469 |
+
if isinstance(nodes, gast.Lambda):
|
| 470 |
+
nodes = gast.Assign(
|
| 471 |
+
targets=[
|
| 472 |
+
gast.Name(
|
| 473 |
+
ctx.info.name,
|
| 474 |
+
ctx=gast.Store(),
|
| 475 |
+
annotation=None,
|
| 476 |
+
type_comment=None)
|
| 477 |
+
],
|
| 478 |
+
value=nodes)
|
| 479 |
+
else:
|
| 480 |
+
nodes.name = ctx.info.name
|
| 481 |
+
|
| 482 |
+
if logging.has_verbosity(2):
|
| 483 |
+
logging.log(2, 'Transformed %s:\n\n%s\n', fn, parser.unparse(nodes))
|
| 484 |
+
|
| 485 |
+
factory = _PythonFnFactory(
|
| 486 |
+
ctx.info.name, fn.__code__.co_freevars, self.get_extra_locals())
|
| 487 |
+
factory.create(
|
| 488 |
+
nodes, ctx.namer, future_features=ctx.info.future_features)
|
| 489 |
+
self._cache[fn][cache_subkey] = factory
|
| 490 |
+
|
| 491 |
+
transformed_fn = factory.instantiate(
|
| 492 |
+
globals_=fn.__globals__,
|
| 493 |
+
closure=fn.__closure__ or (),
|
| 494 |
+
defaults=fn.__defaults__,
|
| 495 |
+
kwdefaults=getattr(fn, '__kwdefaults__', None))
|
| 496 |
+
return transformed_fn, factory.module, factory.source_map
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__init__.py
ADDED
|
File without changes
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (200 Bytes). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/client_lib.cpython-310.pyc
ADDED
|
Binary file (644 Bytes). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/device_lib.cpython-310.pyc
ADDED
|
Binary file (1.27 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/pywrap_tf_session.cpython-310.pyc
ADDED
|
Binary file (1.61 kB). View file
|
|
|
SwarmUI/dlbackend/ComfyUI/venv/lib/python3.10/site-packages/tensorflow/python/client/__pycache__/session.cpython-310.pyc
ADDED
|
Binary file (61.5 kB). View file
|
|
|