pytecode 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytecode/__init__.py +22 -0
- pytecode/analysis.py +2402 -0
- pytecode/attributes.py +868 -0
- pytecode/bytes_utils.py +208 -0
- pytecode/class_reader.py +810 -0
- pytecode/class_writer.py +630 -0
- pytecode/constant_pool.py +196 -0
- pytecode/constant_pool_builder.py +844 -0
- pytecode/constants.py +208 -0
- pytecode/debug_info.py +319 -0
- pytecode/descriptors.py +791 -0
- pytecode/hierarchy.py +561 -0
- pytecode/info.py +123 -0
- pytecode/instructions.py +495 -0
- pytecode/jar.py +271 -0
- pytecode/labels.py +1041 -0
- pytecode/model.py +929 -0
- pytecode/modified_utf8.py +145 -0
- pytecode/operands.py +683 -0
- pytecode/py.typed +0 -0
- pytecode/transforms.py +954 -0
- pytecode/verify.py +1386 -0
- pytecode-0.0.1.dist-info/METADATA +218 -0
- pytecode-0.0.1.dist-info/RECORD +27 -0
- pytecode-0.0.1.dist-info/WHEEL +5 -0
- pytecode-0.0.1.dist-info/licenses/LICENSE +21 -0
- pytecode-0.0.1.dist-info/top_level.txt +1 -0
pytecode/constants.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Constants for JVM class file parsing (JVMS §4)."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum, IntEnum, IntFlag
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"ClassAccessFlag",
|
|
7
|
+
"FieldAccessFlag",
|
|
8
|
+
"MAGIC",
|
|
9
|
+
"MethodAccessFlag",
|
|
10
|
+
"MethodParameterAccessFlag",
|
|
11
|
+
"ModuleAccessFlag",
|
|
12
|
+
"ModuleExportsAccessFlag",
|
|
13
|
+
"ModuleOpensAccessFlag",
|
|
14
|
+
"ModuleRequiresAccessFlag",
|
|
15
|
+
"NestedClassAccessFlag",
|
|
16
|
+
"TargetInfoType",
|
|
17
|
+
"TargetType",
|
|
18
|
+
"TypePathKind",
|
|
19
|
+
"VerificationType",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
MAGIC = 0xCAFEBABE
|
|
23
|
+
"""The magic number identifying a valid Java class file (§4.1)."""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ModuleAccessFlag(IntFlag):
|
|
27
|
+
"""Access flags for modules (§4.7.25, Table 4.7.25-A)."""
|
|
28
|
+
|
|
29
|
+
OPEN = 0x0020
|
|
30
|
+
SYNTHETIC = 0x1000
|
|
31
|
+
MANDATED = 0x8000
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ModuleRequiresAccessFlag(IntFlag):
|
|
35
|
+
"""Access flags for module requires directives (§4.7.25, Table 4.7.25-B)."""
|
|
36
|
+
|
|
37
|
+
TRANSITIVE = 0x0020
|
|
38
|
+
STATIC_PHASE = 0x0040
|
|
39
|
+
SYNTHETIC = 0x1000
|
|
40
|
+
MANDATED = 0x8000
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ModuleExportsAccessFlag(IntFlag):
|
|
44
|
+
"""Access flags for module exports directives (§4.7.25, Table 4.7.25-C)."""
|
|
45
|
+
|
|
46
|
+
SYNTHETIC = 0x1000
|
|
47
|
+
MANDATED = 0x8000
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ModuleOpensAccessFlag(IntFlag):
|
|
51
|
+
"""Access flags for module opens directives (§4.7.25, Table 4.7.25-D)."""
|
|
52
|
+
|
|
53
|
+
SYNTHETIC = 0x1000
|
|
54
|
+
MANDATED = 0x8000
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ClassAccessFlag(IntFlag):
|
|
58
|
+
"""Access flags for classes (§4.1, Table 4.1-B)."""
|
|
59
|
+
|
|
60
|
+
PUBLIC = 0x0001
|
|
61
|
+
FINAL = 0x0010
|
|
62
|
+
SUPER = 0x0020
|
|
63
|
+
INTERFACE = 0x0200
|
|
64
|
+
ABSTRACT = 0x0400
|
|
65
|
+
SYNTHETIC = 0x1000
|
|
66
|
+
ANNOTATION = 0x2000
|
|
67
|
+
ENUM = 0x4000
|
|
68
|
+
MODULE = 0x8000
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class NestedClassAccessFlag(IntFlag):
|
|
72
|
+
"""Access flags for nested classes (§4.7.6, Table 4.7.6-A)."""
|
|
73
|
+
|
|
74
|
+
PUBLIC = 0x0001
|
|
75
|
+
PRIVATE = 0x0002
|
|
76
|
+
PROTECTED = 0x0004
|
|
77
|
+
STATIC = 0x0008
|
|
78
|
+
FINAL = 0x0010
|
|
79
|
+
INTERFACE = 0x0200
|
|
80
|
+
ABSTRACT = 0x0400
|
|
81
|
+
SYNTHETIC = 0x1000
|
|
82
|
+
ANNOTATION = 0x2000
|
|
83
|
+
ENUM = 0x4000
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class MethodAccessFlag(IntFlag):
|
|
87
|
+
"""Access flags for methods (§4.6, Table 4.6-A)."""
|
|
88
|
+
|
|
89
|
+
PUBLIC = 0x0001
|
|
90
|
+
PRIVATE = 0x0002
|
|
91
|
+
PROTECTED = 0x0004
|
|
92
|
+
STATIC = 0x0008
|
|
93
|
+
FINAL = 0x0010
|
|
94
|
+
SYNCHRONIZED = 0x0020
|
|
95
|
+
BRIDGE = 0x0040
|
|
96
|
+
VARARGS = 0x0080
|
|
97
|
+
NATIVE = 0x0100
|
|
98
|
+
ABSTRACT = 0x0400
|
|
99
|
+
STRICT = 0x0800
|
|
100
|
+
SYNTHETIC = 0x1000
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class MethodParameterAccessFlag(IntFlag):
|
|
104
|
+
"""Access flags for method parameters (§4.7.24, Table 4.7.24-A)."""
|
|
105
|
+
|
|
106
|
+
FINAL = 0x0010
|
|
107
|
+
SYNTHETIC = 0x1000
|
|
108
|
+
MANDATED = 0x8000
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class FieldAccessFlag(IntFlag):
|
|
112
|
+
"""Access flags for fields (§4.5, Table 4.5-A)."""
|
|
113
|
+
|
|
114
|
+
PUBLIC = 0x0001
|
|
115
|
+
PRIVATE = 0x0002
|
|
116
|
+
PROTECTED = 0x0004
|
|
117
|
+
STATIC = 0x0008
|
|
118
|
+
FINAL = 0x0010
|
|
119
|
+
VOLATILE = 0x0040
|
|
120
|
+
TRANSIENT = 0x0080
|
|
121
|
+
SYNTHETIC = 0x1000
|
|
122
|
+
ENUM = 0x4000
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TargetType(IntEnum):
|
|
126
|
+
"""Target type values for type annotations (§4.7.20, Table 4.7.20-A/B)."""
|
|
127
|
+
|
|
128
|
+
TYPE_PARAMETER_GENERIC_CLASS_OR_INTERFACE = 0x00
|
|
129
|
+
TYPE_PARAMETER_GENERIC_METHOD_OR_CONSTRUCTOR = 0x01
|
|
130
|
+
SUPERTYPE = 0x10
|
|
131
|
+
TYPE_PARAMETER_BOUND_GENERIC_CLASS_OR_INTERFACE = 0x11
|
|
132
|
+
TYPE_PARAMETER_BOUND_GENERIC_METHOD_OR_CONSTRUCTOR = 0x12
|
|
133
|
+
TYPE_IN_FIELD_OR_RECORD = 0x13
|
|
134
|
+
RETURN_OR_OBJECT_TYPE = 0x14
|
|
135
|
+
RECEIVER_TYPE_METHOD_OR_CONSTRUCTOR = 0x15
|
|
136
|
+
FORMAL_PARAMETER_METHOD_CONSTRUCTOR_OR_LAMBDA = 0x16
|
|
137
|
+
TYPE_THROWS = 0x17
|
|
138
|
+
TYPE_LOCAL_VARIABLE = 0x40
|
|
139
|
+
TYPE_RESOURCE_VARIABLE = 0x41
|
|
140
|
+
TYPE_EXCEPTION_PARAMETER = 0x42
|
|
141
|
+
TYPE_INSTANCEOF = 0x43
|
|
142
|
+
TYPE_NEW = 0x44
|
|
143
|
+
TYPE_METHOD_NEW = 0x45
|
|
144
|
+
TYPE_METHOD_IDENTIFIER = 0x46
|
|
145
|
+
TYPE_CAST = 0x47
|
|
146
|
+
TYPE_GENERIC_CONSTRUCTOR = 0x48
|
|
147
|
+
TYPE_GENERIC_METHOD = 0x49
|
|
148
|
+
TYPE_GENERIC_CONSTRUCTOR_NEW = 0x4A
|
|
149
|
+
TYPE_GENERIC_METHOD_IDENTIFIER = 0x4B
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class TargetInfoType(Enum):
|
|
153
|
+
"""Mapping from target_info union discriminants to target types (§4.7.20.1)."""
|
|
154
|
+
|
|
155
|
+
TYPE_PARAMETER = (
|
|
156
|
+
TargetType.TYPE_PARAMETER_GENERIC_CLASS_OR_INTERFACE,
|
|
157
|
+
TargetType.TYPE_PARAMETER_GENERIC_METHOD_OR_CONSTRUCTOR,
|
|
158
|
+
)
|
|
159
|
+
SUPERTYPE = (TargetType.SUPERTYPE,)
|
|
160
|
+
TYPE_PARAMETER_BOUND = (
|
|
161
|
+
TargetType.TYPE_PARAMETER_BOUND_GENERIC_CLASS_OR_INTERFACE,
|
|
162
|
+
TargetType.TYPE_PARAMETER_BOUND_GENERIC_METHOD_OR_CONSTRUCTOR,
|
|
163
|
+
)
|
|
164
|
+
EMPTY = (
|
|
165
|
+
TargetType.TYPE_IN_FIELD_OR_RECORD,
|
|
166
|
+
TargetType.RETURN_OR_OBJECT_TYPE,
|
|
167
|
+
TargetType.RECEIVER_TYPE_METHOD_OR_CONSTRUCTOR,
|
|
168
|
+
)
|
|
169
|
+
FORMAL_PARAMETER = (TargetType.FORMAL_PARAMETER_METHOD_CONSTRUCTOR_OR_LAMBDA,)
|
|
170
|
+
THROWS = (TargetType.TYPE_THROWS,)
|
|
171
|
+
LOCALVAR = (TargetType.TYPE_LOCAL_VARIABLE, TargetType.TYPE_RESOURCE_VARIABLE)
|
|
172
|
+
CATCH = (TargetType.TYPE_EXCEPTION_PARAMETER,)
|
|
173
|
+
OFFSET = (
|
|
174
|
+
TargetType.TYPE_INSTANCEOF,
|
|
175
|
+
TargetType.TYPE_NEW,
|
|
176
|
+
TargetType.TYPE_METHOD_NEW,
|
|
177
|
+
TargetType.TYPE_METHOD_IDENTIFIER,
|
|
178
|
+
)
|
|
179
|
+
TYPE_ARGUMENT = (
|
|
180
|
+
TargetType.TYPE_CAST,
|
|
181
|
+
TargetType.TYPE_GENERIC_CONSTRUCTOR,
|
|
182
|
+
TargetType.TYPE_GENERIC_METHOD,
|
|
183
|
+
TargetType.TYPE_GENERIC_CONSTRUCTOR_NEW,
|
|
184
|
+
TargetType.TYPE_GENERIC_METHOD_IDENTIFIER,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class TypePathKind(IntEnum):
|
|
189
|
+
"""Kind values for type_path entries in type annotations (§4.7.20.2, Table 4.7.20.2-A)."""
|
|
190
|
+
|
|
191
|
+
ARRAY_TYPE = 0
|
|
192
|
+
NESTED_TYPE = 1
|
|
193
|
+
WILDCARD_TYPE = 2
|
|
194
|
+
PARAMETERIZED_TYPE = 3
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class VerificationType(IntEnum):
|
|
198
|
+
"""Verification type info tags for StackMapTable entries (§4.7.4, Table 4.7.4-A)."""
|
|
199
|
+
|
|
200
|
+
TOP = 0
|
|
201
|
+
INTEGER = 1
|
|
202
|
+
FLOAT = 2
|
|
203
|
+
DOUBLE = 3
|
|
204
|
+
LONG = 4
|
|
205
|
+
NULL = 5
|
|
206
|
+
UNINITIALIZED_THIS = 6
|
|
207
|
+
OBJECT = 7
|
|
208
|
+
UNINITIALIZED = 8
|
pytecode/debug_info.py
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"""Utilities for managing JVM debug information in class files.
|
|
2
|
+
|
|
3
|
+
Provides policies, state tracking, and stripping helpers for debug
|
|
4
|
+
attributes such as line numbers, local variables, and source file
|
|
5
|
+
references.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from enum import Enum
|
|
11
|
+
from typing import TYPE_CHECKING, overload
|
|
12
|
+
|
|
13
|
+
from .attributes import AttributeInfo, MethodParametersAttr, SourceDebugExtensionAttr, SourceFileAttr
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from .model import ClassModel, CodeModel, MethodModel
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"DebugInfoPolicy",
|
|
20
|
+
"DebugInfoState",
|
|
21
|
+
"apply_debug_info_policy",
|
|
22
|
+
"has_class_debug_info",
|
|
23
|
+
"has_code_debug_info",
|
|
24
|
+
"is_class_debug_info_stale",
|
|
25
|
+
"is_code_debug_info_stale",
|
|
26
|
+
"mark_class_debug_info_stale",
|
|
27
|
+
"mark_code_debug_info_stale",
|
|
28
|
+
"normalize_debug_info_policy",
|
|
29
|
+
"skip_debug_method_attributes",
|
|
30
|
+
"strip_class_debug_attributes",
|
|
31
|
+
"strip_debug_info",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class DebugInfoPolicy(Enum):
|
|
36
|
+
"""Policy controlling how debug information is handled.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
PRESERVE: Keep existing debug information unchanged.
|
|
40
|
+
STRIP: Remove all debug information from the target.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
PRESERVE = "preserve"
|
|
44
|
+
STRIP = "strip"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class DebugInfoState(Enum):
|
|
48
|
+
"""Staleness state of debug information on a model.
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
FRESH: Debug information is up to date.
|
|
52
|
+
STALE: Debug information may be outdated due to bytecode changes.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
FRESH = "fresh"
|
|
56
|
+
STALE = "stale"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def normalize_debug_info_policy(policy: DebugInfoPolicy | str) -> DebugInfoPolicy:
|
|
60
|
+
"""Coerce a string or enum value into a ``DebugInfoPolicy``.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
policy: A ``DebugInfoPolicy`` member or its string value.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
The corresponding ``DebugInfoPolicy`` member.
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
ValueError: If the string does not match any policy value.
|
|
70
|
+
"""
|
|
71
|
+
if isinstance(policy, DebugInfoPolicy):
|
|
72
|
+
return policy
|
|
73
|
+
try:
|
|
74
|
+
return DebugInfoPolicy(policy)
|
|
75
|
+
except ValueError as exc:
|
|
76
|
+
expected = ", ".join(member.value for member in DebugInfoPolicy)
|
|
77
|
+
raise ValueError(f"debug_info must be one of: {expected}") from exc
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def strip_class_debug_attributes(attributes: list[AttributeInfo]) -> list[AttributeInfo]:
|
|
81
|
+
"""Filter out class-level debug attributes from a list.
|
|
82
|
+
|
|
83
|
+
Removes ``SourceFileAttr`` and ``SourceDebugExtensionAttr`` entries,
|
|
84
|
+
returning only the non-debug attributes.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
attributes: The attribute list to filter.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
A new list with class-level debug attributes removed.
|
|
91
|
+
"""
|
|
92
|
+
return [
|
|
93
|
+
attribute for attribute in attributes if not isinstance(attribute, (SourceFileAttr, SourceDebugExtensionAttr))
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def skip_debug_method_attributes(attributes: list[AttributeInfo]) -> list[AttributeInfo]:
|
|
98
|
+
"""Filter out method-level debug attributes from a list.
|
|
99
|
+
|
|
100
|
+
Removes ``MethodParametersAttr`` entries, returning only the
|
|
101
|
+
remaining attributes.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
attributes: The attribute list to filter.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
A new list with method-level debug attributes removed.
|
|
108
|
+
"""
|
|
109
|
+
return [attribute for attribute in attributes if not isinstance(attribute, MethodParametersAttr)]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def has_class_debug_info(target: ClassModel) -> bool:
|
|
113
|
+
"""Check whether a class model contains class-level debug attributes.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
target: The class model to inspect.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
``True`` if the class has ``SourceFileAttr`` or
|
|
120
|
+
``SourceDebugExtensionAttr`` attributes.
|
|
121
|
+
"""
|
|
122
|
+
return any(isinstance(attribute, (SourceFileAttr, SourceDebugExtensionAttr)) for attribute in target.attributes)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def has_code_debug_info(target: CodeModel) -> bool:
|
|
126
|
+
"""Check whether a code model contains code-level debug information.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
target: The code model to inspect.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
``True`` if the code has line numbers, local variables, or local
|
|
133
|
+
variable type entries.
|
|
134
|
+
"""
|
|
135
|
+
return bool(target.line_numbers or target.local_variables or target.local_variable_types)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def is_class_debug_info_stale(target: ClassModel) -> bool:
|
|
139
|
+
"""Check whether a class model has stale class-level debug info.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
target: The class model to inspect.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
``True`` if the debug state is stale and debug attributes are present.
|
|
146
|
+
"""
|
|
147
|
+
return target.debug_info_state is DebugInfoState.STALE and has_class_debug_info(target)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def is_code_debug_info_stale(target: CodeModel) -> bool:
|
|
151
|
+
"""Check whether a code model has stale code-level debug info.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
target: The code model to inspect.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
``True`` if the debug state is stale and debug information is present.
|
|
158
|
+
"""
|
|
159
|
+
return target.debug_info_state is DebugInfoState.STALE and has_code_debug_info(target)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def mark_class_debug_info_stale(target: ClassModel) -> ClassModel:
|
|
163
|
+
"""Mark a class model's debug information as stale.
|
|
164
|
+
|
|
165
|
+
If the class has debug attributes, sets its debug state to
|
|
166
|
+
``DebugInfoState.STALE``.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
target: The class model to mark.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
The same class model, possibly with updated debug state.
|
|
173
|
+
"""
|
|
174
|
+
if has_class_debug_info(target):
|
|
175
|
+
target.debug_info_state = DebugInfoState.STALE
|
|
176
|
+
return target
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@overload
|
|
180
|
+
def mark_code_debug_info_stale(target: CodeModel) -> CodeModel: ...
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@overload
|
|
184
|
+
def mark_code_debug_info_stale(target: MethodModel) -> MethodModel: ...
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@overload
|
|
188
|
+
def mark_code_debug_info_stale(target: ClassModel) -> ClassModel: ...
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def mark_code_debug_info_stale(target: object) -> object:
|
|
192
|
+
"""Mark code-level debug information as stale.
|
|
193
|
+
|
|
194
|
+
Accepts a ``CodeModel``, ``MethodModel``, or ``ClassModel``. For a
|
|
195
|
+
``CodeModel``, sets its state to stale if it has debug info. For a
|
|
196
|
+
``MethodModel``, delegates to its code attribute. For a ``ClassModel``,
|
|
197
|
+
recursively marks all methods.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
target: The model whose code debug info should be marked stale.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
The same model, possibly with updated debug state.
|
|
204
|
+
|
|
205
|
+
Raises:
|
|
206
|
+
TypeError: If *target* is not a supported model type.
|
|
207
|
+
"""
|
|
208
|
+
from .model import ClassModel, CodeModel, MethodModel
|
|
209
|
+
|
|
210
|
+
if isinstance(target, CodeModel):
|
|
211
|
+
if has_code_debug_info(target):
|
|
212
|
+
target.debug_info_state = DebugInfoState.STALE
|
|
213
|
+
return target
|
|
214
|
+
if isinstance(target, MethodModel):
|
|
215
|
+
if target.code is not None:
|
|
216
|
+
mark_code_debug_info_stale(target.code)
|
|
217
|
+
return target
|
|
218
|
+
if isinstance(target, ClassModel):
|
|
219
|
+
for method in target.methods:
|
|
220
|
+
mark_code_debug_info_stale(method)
|
|
221
|
+
return target
|
|
222
|
+
raise TypeError("code-debug helper expects a CodeModel, MethodModel, or ClassModel")
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@overload
|
|
226
|
+
def apply_debug_info_policy(target: CodeModel, policy: DebugInfoPolicy | str) -> CodeModel: ...
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@overload
|
|
230
|
+
def apply_debug_info_policy(target: MethodModel, policy: DebugInfoPolicy | str) -> MethodModel: ...
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@overload
|
|
234
|
+
def apply_debug_info_policy(target: ClassModel, policy: DebugInfoPolicy | str) -> ClassModel: ...
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def apply_debug_info_policy(target: object, policy: DebugInfoPolicy | str) -> object:
|
|
238
|
+
"""Apply a debug information policy to a model.
|
|
239
|
+
|
|
240
|
+
When the policy is ``STRIP``, removes all debug information from the
|
|
241
|
+
target. When the policy is ``PRESERVE``, leaves the target unchanged.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
target: The model to apply the policy to.
|
|
245
|
+
policy: The policy to apply, as an enum member or string.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
The same model, with debug information stripped if requested.
|
|
249
|
+
|
|
250
|
+
Raises:
|
|
251
|
+
TypeError: If *target* is not a supported model type.
|
|
252
|
+
ValueError: If *policy* is an invalid string.
|
|
253
|
+
"""
|
|
254
|
+
from .model import ClassModel, CodeModel, MethodModel
|
|
255
|
+
|
|
256
|
+
debug_policy = normalize_debug_info_policy(policy)
|
|
257
|
+
if isinstance(target, CodeModel):
|
|
258
|
+
if debug_policy is DebugInfoPolicy.STRIP:
|
|
259
|
+
strip_debug_info(target)
|
|
260
|
+
return target
|
|
261
|
+
if isinstance(target, MethodModel):
|
|
262
|
+
if debug_policy is DebugInfoPolicy.STRIP:
|
|
263
|
+
strip_debug_info(target)
|
|
264
|
+
return target
|
|
265
|
+
if isinstance(target, ClassModel):
|
|
266
|
+
if debug_policy is DebugInfoPolicy.STRIP:
|
|
267
|
+
strip_debug_info(target)
|
|
268
|
+
return target
|
|
269
|
+
raise TypeError("debug-info helpers expect a CodeModel, MethodModel, or ClassModel")
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@overload
|
|
273
|
+
def strip_debug_info(target: CodeModel) -> CodeModel: ...
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@overload
|
|
277
|
+
def strip_debug_info(target: MethodModel) -> MethodModel: ...
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
@overload
|
|
281
|
+
def strip_debug_info(target: ClassModel) -> ClassModel: ...
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def strip_debug_info(target: object) -> object:
|
|
285
|
+
"""Remove all debug information from a model.
|
|
286
|
+
|
|
287
|
+
For a ``CodeModel``, clears line numbers, local variables, and local
|
|
288
|
+
variable types. For a ``MethodModel``, delegates to its code attribute.
|
|
289
|
+
For a ``ClassModel``, strips class-level debug attributes and recurses
|
|
290
|
+
into all methods.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
target: The model to strip debug information from.
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
The same model with debug information removed and state set to fresh.
|
|
297
|
+
|
|
298
|
+
Raises:
|
|
299
|
+
TypeError: If *target* is not a supported model type.
|
|
300
|
+
"""
|
|
301
|
+
from .model import ClassModel, CodeModel, MethodModel
|
|
302
|
+
|
|
303
|
+
if isinstance(target, CodeModel):
|
|
304
|
+
target.line_numbers.clear()
|
|
305
|
+
target.local_variables.clear()
|
|
306
|
+
target.local_variable_types.clear()
|
|
307
|
+
target.debug_info_state = DebugInfoState.FRESH
|
|
308
|
+
return target
|
|
309
|
+
if isinstance(target, MethodModel):
|
|
310
|
+
if target.code is not None:
|
|
311
|
+
strip_debug_info(target.code)
|
|
312
|
+
return target
|
|
313
|
+
if isinstance(target, ClassModel):
|
|
314
|
+
target.attributes[:] = strip_class_debug_attributes(target.attributes)
|
|
315
|
+
target.debug_info_state = DebugInfoState.FRESH
|
|
316
|
+
for method in target.methods:
|
|
317
|
+
strip_debug_info(method)
|
|
318
|
+
return target
|
|
319
|
+
raise TypeError("debug-info helpers expect a CodeModel, MethodModel, or ClassModel")
|