pytecode 0.0.2__tar.gz → 0.0.3__tar.gz
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-0.0.2/pytecode.egg-info → pytecode-0.0.3}/PKG-INFO +11 -11
- {pytecode-0.0.2 → pytecode-0.0.3}/README.md +10 -10
- {pytecode-0.0.2 → pytecode-0.0.3}/pyproject.toml +2 -2
- {pytecode-0.0.2 → pytecode-0.0.3}/pytecode/__init__.py +5 -5
- pytecode-0.0.3/pytecode/_internal/__init__.py +1 -0
- pytecode-0.0.2/pytecode/analysis.py → pytecode-0.0.3/pytecode/analysis/__init__.py +14 -14
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/analysis}/hierarchy.py +5 -5
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/analysis}/verify.py +10 -10
- pytecode-0.0.2/pytecode/jar.py → pytecode-0.0.3/pytecode/archive/__init__.py +5 -5
- pytecode-0.0.3/pytecode/classfile/__init__.py +14 -0
- pytecode-0.0.2/pytecode/class_reader.py → pytecode-0.0.3/pytecode/classfile/reader.py +4 -4
- pytecode-0.0.2/pytecode/class_writer.py → pytecode-0.0.3/pytecode/classfile/writer.py +1 -1
- pytecode-0.0.3/pytecode/edit/__init__.py +12 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/edit}/_attribute_clone.py +1 -1
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/edit}/constant_pool_builder.py +2 -2
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/edit}/debug_info.py +1 -1
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/edit}/labels.py +10 -10
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/edit}/model.py +18 -18
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/edit}/operands.py +1 -1
- pytecode-0.0.2/pytecode/transforms.py → pytecode-0.0.3/pytecode/transforms/__init__.py +3 -3
- {pytecode-0.0.2 → pytecode-0.0.3/pytecode.egg-info}/PKG-INFO +11 -11
- {pytecode-0.0.2 → pytecode-0.0.3}/pytecode.egg-info/SOURCES.txt +24 -21
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_analysis.py +45 -56
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_api_docs.py +6 -6
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_attributes.py +4 -1
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_bytes_utils.py +1 -1
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_cfg_oracle.py +4 -8
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_class_reader.py +7 -4
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_class_writer.py +7 -4
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_constant_pool.py +3 -3
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_constant_pool_builder.py +4 -4
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_debug_info.py +22 -150
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_descriptors.py +2 -2
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_helpers.py +122 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_hierarchy.py +5 -5
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_instructions.py +1 -1
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_jar.py +8 -14
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_labels.py +19 -126
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_model.py +45 -57
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_modified_utf8.py +1 -1
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_operands.py +16 -25
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_transforms.py +3 -3
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_validation.py +2 -2
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_verify.py +31 -31
- {pytecode-0.0.2 → pytecode-0.0.3}/LICENSE +0 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/MANIFEST.in +0 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/_internal}/bytes_utils.py +0 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/classfile}/attributes.py +0 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/classfile}/constant_pool.py +0 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/classfile}/constants.py +0 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/classfile}/descriptors.py +0 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/classfile}/info.py +0 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/classfile}/instructions.py +0 -0
- {pytecode-0.0.2/pytecode → pytecode-0.0.3/pytecode/classfile}/modified_utf8.py +0 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/pytecode/py.typed +0 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/pytecode.egg-info/dependency_links.txt +0 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/pytecode.egg-info/requires.txt +0 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/pytecode.egg-info/top_level.txt +0 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/setup.cfg +0 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_javap_parser.py +0 -0
- {pytecode-0.0.2 → pytecode-0.0.3}/tests/test_validate_release_tag.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytecode
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Python library for parsing, manipulating, and emitting JVM class files
|
|
5
5
|
Author: Trenton Smith
|
|
6
6
|
License-Expression: MIT
|
|
@@ -95,8 +95,8 @@ Use `recompute_frames=True` when an edit changes control flow or stack/local lay
|
|
|
95
95
|
|
|
96
96
|
```python
|
|
97
97
|
from pytecode import JarFile
|
|
98
|
-
from pytecode.constants import MethodAccessFlag
|
|
99
|
-
from pytecode.model import ClassModel, MethodModel
|
|
98
|
+
from pytecode.classfile.constants import MethodAccessFlag
|
|
99
|
+
from pytecode.edit.model import ClassModel, MethodModel
|
|
100
100
|
from pytecode.transforms import (
|
|
101
101
|
class_named,
|
|
102
102
|
method_is_public,
|
|
@@ -136,15 +136,15 @@ Top-level exports:
|
|
|
136
136
|
Supported submodules:
|
|
137
137
|
|
|
138
138
|
- `pytecode.transforms` for composable class, field, method, and code transforms.
|
|
139
|
-
- `pytecode.labels` for label-aware bytecode editing helpers.
|
|
140
|
-
- `pytecode.operands` for symbolic operand wrappers.
|
|
139
|
+
- `pytecode.edit.labels` for label-aware bytecode editing helpers.
|
|
140
|
+
- `pytecode.edit.operands` for symbolic operand wrappers.
|
|
141
141
|
- `pytecode.analysis` for CFG construction, frame simulation, and recomputation helpers.
|
|
142
|
-
- `pytecode.verify` for structural validation and diagnostics.
|
|
143
|
-
- `pytecode.hierarchy` for type and override resolution helpers.
|
|
144
|
-
- `pytecode.descriptors` for JVM descriptors and generic signatures.
|
|
145
|
-
- `pytecode.constant_pool_builder` for deterministic constant-pool construction.
|
|
146
|
-
- `pytecode.modified_utf8` for JVM Modified UTF-8 encoding and decoding.
|
|
147
|
-
- `pytecode.debug_info` for explicit debug-info preservation and stripping policies.
|
|
142
|
+
- `pytecode.analysis.verify` for structural validation and diagnostics.
|
|
143
|
+
- `pytecode.analysis.hierarchy` for type and override resolution helpers.
|
|
144
|
+
- `pytecode.classfile.descriptors` for JVM descriptors and generic signatures.
|
|
145
|
+
- `pytecode.edit.constant_pool_builder` for deterministic constant-pool construction.
|
|
146
|
+
- `pytecode.classfile.modified_utf8` for JVM Modified UTF-8 encoding and decoding.
|
|
147
|
+
- `pytecode.edit.debug_info` for explicit debug-info preservation and stripping policies.
|
|
148
148
|
|
|
149
149
|
## Documentation
|
|
150
150
|
|
|
@@ -69,8 +69,8 @@ Use `recompute_frames=True` when an edit changes control flow or stack/local lay
|
|
|
69
69
|
|
|
70
70
|
```python
|
|
71
71
|
from pytecode import JarFile
|
|
72
|
-
from pytecode.constants import MethodAccessFlag
|
|
73
|
-
from pytecode.model import ClassModel, MethodModel
|
|
72
|
+
from pytecode.classfile.constants import MethodAccessFlag
|
|
73
|
+
from pytecode.edit.model import ClassModel, MethodModel
|
|
74
74
|
from pytecode.transforms import (
|
|
75
75
|
class_named,
|
|
76
76
|
method_is_public,
|
|
@@ -110,15 +110,15 @@ Top-level exports:
|
|
|
110
110
|
Supported submodules:
|
|
111
111
|
|
|
112
112
|
- `pytecode.transforms` for composable class, field, method, and code transforms.
|
|
113
|
-
- `pytecode.labels` for label-aware bytecode editing helpers.
|
|
114
|
-
- `pytecode.operands` for symbolic operand wrappers.
|
|
113
|
+
- `pytecode.edit.labels` for label-aware bytecode editing helpers.
|
|
114
|
+
- `pytecode.edit.operands` for symbolic operand wrappers.
|
|
115
115
|
- `pytecode.analysis` for CFG construction, frame simulation, and recomputation helpers.
|
|
116
|
-
- `pytecode.verify` for structural validation and diagnostics.
|
|
117
|
-
- `pytecode.hierarchy` for type and override resolution helpers.
|
|
118
|
-
- `pytecode.descriptors` for JVM descriptors and generic signatures.
|
|
119
|
-
- `pytecode.constant_pool_builder` for deterministic constant-pool construction.
|
|
120
|
-
- `pytecode.modified_utf8` for JVM Modified UTF-8 encoding and decoding.
|
|
121
|
-
- `pytecode.debug_info` for explicit debug-info preservation and stripping policies.
|
|
116
|
+
- `pytecode.analysis.verify` for structural validation and diagnostics.
|
|
117
|
+
- `pytecode.analysis.hierarchy` for type and override resolution helpers.
|
|
118
|
+
- `pytecode.classfile.descriptors` for JVM descriptors and generic signatures.
|
|
119
|
+
- `pytecode.edit.constant_pool_builder` for deterministic constant-pool construction.
|
|
120
|
+
- `pytecode.classfile.modified_utf8` for JVM Modified UTF-8 encoding and decoding.
|
|
121
|
+
- `pytecode.edit.debug_info` for explicit debug-info preservation and stripping policies.
|
|
122
122
|
|
|
123
123
|
## Documentation
|
|
124
124
|
|
|
@@ -6,14 +6,14 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
include-package-data = true
|
|
7
7
|
|
|
8
8
|
[tool.setuptools.packages.find]
|
|
9
|
-
include = ["pytecode"]
|
|
9
|
+
include = ["pytecode*"]
|
|
10
10
|
|
|
11
11
|
[tool.setuptools.package-data]
|
|
12
12
|
pytecode = ["py.typed"]
|
|
13
13
|
|
|
14
14
|
[project]
|
|
15
15
|
name = "pytecode"
|
|
16
|
-
version = "0.0.
|
|
16
|
+
version = "0.0.3"
|
|
17
17
|
description = "Python library for parsing, manipulating, and emitting JVM class files"
|
|
18
18
|
readme = "README.md"
|
|
19
19
|
authors = [{ name = "Trenton Smith" }]
|
|
@@ -11,12 +11,12 @@ Provides four top-level entry points:
|
|
|
11
11
|
Additional submodules expose transforms, descriptors, analysis, hierarchy
|
|
12
12
|
resolution, validation, operands, labels, debug-info helpers, and the
|
|
13
13
|
underlying data types. See ``pytecode.transforms``, ``pytecode.analysis``,
|
|
14
|
-
``pytecode.verify``, and the other documented submodules for details.
|
|
14
|
+
``pytecode.analysis.verify``, and the other documented submodules for details.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
from .
|
|
18
|
-
from .
|
|
19
|
-
from .
|
|
20
|
-
from .model import ClassModel
|
|
17
|
+
from .archive import JarFile
|
|
18
|
+
from .classfile.reader import ClassReader
|
|
19
|
+
from .classfile.writer import ClassWriter
|
|
20
|
+
from .edit.model import ClassModel
|
|
21
21
|
|
|
22
22
|
__all__ = ["ClassModel", "ClassReader", "ClassWriter", "JarFile"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Internal implementation helpers for pytecode."""
|
|
@@ -27,7 +27,7 @@ from collections.abc import Sequence
|
|
|
27
27
|
from dataclasses import dataclass
|
|
28
28
|
from typing import TYPE_CHECKING
|
|
29
29
|
|
|
30
|
-
from .attributes import (
|
|
30
|
+
from ..classfile.attributes import (
|
|
31
31
|
AppendFrameInfo,
|
|
32
32
|
ChopFrameInfo,
|
|
33
33
|
DoubleVariableInfo,
|
|
@@ -48,11 +48,11 @@ from .attributes import (
|
|
|
48
48
|
UninitializedVariableInfo,
|
|
49
49
|
VerificationTypeInfo,
|
|
50
50
|
)
|
|
51
|
-
from .constants import VerificationType
|
|
52
|
-
from .descriptors import (
|
|
51
|
+
from ..classfile.constants import VerificationType
|
|
52
|
+
from ..classfile.descriptors import (
|
|
53
53
|
ArrayType as DescArrayType,
|
|
54
54
|
)
|
|
55
|
-
from .descriptors import (
|
|
55
|
+
from ..classfile.descriptors import (
|
|
56
56
|
BaseType,
|
|
57
57
|
FieldDescriptor,
|
|
58
58
|
ObjectType,
|
|
@@ -60,15 +60,14 @@ from .descriptors import (
|
|
|
60
60
|
parse_field_descriptor,
|
|
61
61
|
parse_method_descriptor,
|
|
62
62
|
)
|
|
63
|
-
from .
|
|
64
|
-
from .instructions import (
|
|
63
|
+
from ..classfile.instructions import (
|
|
65
64
|
ArrayType as InsnArrayType,
|
|
66
65
|
)
|
|
67
|
-
from .instructions import (
|
|
66
|
+
from ..classfile.instructions import (
|
|
68
67
|
InsnInfo,
|
|
69
68
|
InsnInfoType,
|
|
70
69
|
)
|
|
71
|
-
from .labels import (
|
|
70
|
+
from ..edit.labels import (
|
|
72
71
|
BranchInsn,
|
|
73
72
|
CodeItem,
|
|
74
73
|
ExceptionHandler,
|
|
@@ -76,7 +75,7 @@ from .labels import (
|
|
|
76
75
|
LookupSwitchInsn,
|
|
77
76
|
TableSwitchInsn,
|
|
78
77
|
)
|
|
79
|
-
from .operands import (
|
|
78
|
+
from ..edit.operands import (
|
|
80
79
|
FieldInsn,
|
|
81
80
|
IIncInsn,
|
|
82
81
|
InterfaceMethodInsn,
|
|
@@ -95,11 +94,12 @@ from .operands import (
|
|
|
95
94
|
TypeInsn,
|
|
96
95
|
VarInsn,
|
|
97
96
|
)
|
|
97
|
+
from .hierarchy import JAVA_LANG_OBJECT, common_superclass
|
|
98
98
|
|
|
99
99
|
if TYPE_CHECKING:
|
|
100
|
-
from .constant_pool_builder import ConstantPoolBuilder
|
|
100
|
+
from ..edit.constant_pool_builder import ConstantPoolBuilder
|
|
101
|
+
from ..edit.model import CodeModel, MethodModel
|
|
101
102
|
from .hierarchy import ClassResolver
|
|
102
|
-
from .model import CodeModel, MethodModel
|
|
103
103
|
|
|
104
104
|
# ===================================================================
|
|
105
105
|
# Analysis errors
|
|
@@ -435,7 +435,7 @@ def initial_frame(method: MethodModel, class_name: str) -> FrameState:
|
|
|
435
435
|
Returns:
|
|
436
436
|
A ``FrameState`` representing the method entry point.
|
|
437
437
|
"""
|
|
438
|
-
from .constants import MethodAccessFlag
|
|
438
|
+
from ..classfile.constants import MethodAccessFlag
|
|
439
439
|
|
|
440
440
|
md = parse_method_descriptor(method.descriptor)
|
|
441
441
|
locals_list: list[VType] = []
|
|
@@ -1936,7 +1936,7 @@ def _simulate_raw_insn(insn: InsnInfo, state: FrameState) -> FrameState:
|
|
|
1936
1936
|
# --- NEWARRAY ---
|
|
1937
1937
|
if opcode == _T.NEWARRAY:
|
|
1938
1938
|
state, _ = state.pop(1) # pop count
|
|
1939
|
-
from .instructions import NewArray as NewArrayInsn
|
|
1939
|
+
from ..classfile.instructions import NewArray as NewArrayInsn
|
|
1940
1940
|
|
|
1941
1941
|
if isinstance(insn, NewArrayInsn):
|
|
1942
1942
|
array_desc = _NEWARRAY_TYPE_MAP.get(insn.atype, "[I")
|
|
@@ -2279,7 +2279,7 @@ def compute_frames(
|
|
|
2279
2279
|
analysis_code = _prepare_analysis_code(code)
|
|
2280
2280
|
analysis_label_offsets = label_offsets
|
|
2281
2281
|
if analysis_code is not code:
|
|
2282
|
-
from .labels import resolve_labels
|
|
2282
|
+
from ..edit.labels import resolve_labels
|
|
2283
2283
|
|
|
2284
2284
|
analysis_label_offsets = resolve_labels(list(analysis_code.instructions), cp).label_offsets
|
|
2285
2285
|
|
|
@@ -13,13 +13,13 @@ from collections.abc import Iterable, Iterator
|
|
|
13
13
|
from dataclasses import dataclass
|
|
14
14
|
from typing import TYPE_CHECKING, Protocol
|
|
15
15
|
|
|
16
|
-
from .constant_pool import ClassInfo
|
|
17
|
-
from .
|
|
18
|
-
from .
|
|
19
|
-
from .
|
|
16
|
+
from ..classfile.constant_pool import ClassInfo
|
|
17
|
+
from ..classfile.constants import ClassAccessFlag, MethodAccessFlag
|
|
18
|
+
from ..classfile.info import ClassFile
|
|
19
|
+
from ..edit.constant_pool_builder import ConstantPoolBuilder
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
|
-
from .model import ClassModel
|
|
22
|
+
from ..edit.model import ClassModel
|
|
23
23
|
|
|
24
24
|
JAVA_LANG_OBJECT = "java/lang/Object"
|
|
25
25
|
|
|
@@ -15,7 +15,7 @@ from __future__ import annotations
|
|
|
15
15
|
from dataclasses import dataclass, field
|
|
16
16
|
from enum import Enum
|
|
17
17
|
|
|
18
|
-
from .attributes import (
|
|
18
|
+
from ..classfile.attributes import (
|
|
19
19
|
AnnotationDefaultAttr,
|
|
20
20
|
AttributeInfo,
|
|
21
21
|
BootstrapMethodsAttr,
|
|
@@ -41,7 +41,7 @@ from .attributes import (
|
|
|
41
41
|
SourceDebugExtensionAttr,
|
|
42
42
|
StackMapTableAttr,
|
|
43
43
|
)
|
|
44
|
-
from .constant_pool import (
|
|
44
|
+
from ..classfile.constant_pool import (
|
|
45
45
|
ClassInfo,
|
|
46
46
|
ConstantPoolInfo,
|
|
47
47
|
DoubleInfo,
|
|
@@ -61,11 +61,10 @@ from .constant_pool import (
|
|
|
61
61
|
StringInfo,
|
|
62
62
|
Utf8Info,
|
|
63
63
|
)
|
|
64
|
-
from .constants import MAGIC, ClassAccessFlag, FieldAccessFlag, MethodAccessFlag
|
|
65
|
-
from .
|
|
66
|
-
from .
|
|
67
|
-
from .
|
|
68
|
-
from .instructions import (
|
|
64
|
+
from ..classfile.constants import MAGIC, ClassAccessFlag, FieldAccessFlag, MethodAccessFlag
|
|
65
|
+
from ..classfile.descriptors import is_valid_field_descriptor, is_valid_method_descriptor
|
|
66
|
+
from ..classfile.info import ClassFile, FieldInfo, MethodInfo
|
|
67
|
+
from ..classfile.instructions import (
|
|
69
68
|
Branch,
|
|
70
69
|
BranchW,
|
|
71
70
|
ConstPoolIndex,
|
|
@@ -77,14 +76,15 @@ from .instructions import (
|
|
|
77
76
|
MultiANewArray,
|
|
78
77
|
TableSwitch,
|
|
79
78
|
)
|
|
80
|
-
from .
|
|
79
|
+
from ..classfile.modified_utf8 import decode_modified_utf8
|
|
80
|
+
from ..edit.debug_info import is_class_debug_info_stale, is_code_debug_info_stale
|
|
81
|
+
from ..edit.labels import (
|
|
81
82
|
BranchInsn,
|
|
82
83
|
Label,
|
|
83
84
|
LookupSwitchInsn,
|
|
84
85
|
TableSwitchInsn,
|
|
85
86
|
)
|
|
86
|
-
from .model import ClassModel, CodeModel, FieldModel, MethodModel
|
|
87
|
-
from .modified_utf8 import decode_modified_utf8
|
|
87
|
+
from ..edit.model import ClassModel, CodeModel, FieldModel, MethodModel
|
|
88
88
|
|
|
89
89
|
__all__ = [
|
|
90
90
|
"Category",
|
|
@@ -9,11 +9,11 @@ import zipfile
|
|
|
9
9
|
from dataclasses import dataclass
|
|
10
10
|
from pathlib import Path, PurePosixPath
|
|
11
11
|
|
|
12
|
-
from .
|
|
13
|
-
from .
|
|
14
|
-
from .
|
|
15
|
-
from .model import ClassModel
|
|
16
|
-
from
|
|
12
|
+
from ..analysis.hierarchy import ClassResolver
|
|
13
|
+
from ..classfile.reader import ClassReader
|
|
14
|
+
from ..edit.debug_info import DebugInfoPolicy, normalize_debug_info_policy
|
|
15
|
+
from ..edit.model import ClassModel
|
|
16
|
+
from ..transforms import ClassTransform
|
|
17
17
|
|
|
18
18
|
__all__ = ["JarFile", "JarInfo"]
|
|
19
19
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Parsed JVM classfile structures, parsing, and emission."""
|
|
2
|
+
|
|
3
|
+
from .info import ClassFile, FieldInfo, MethodInfo
|
|
4
|
+
from .reader import ClassReader, MalformedClassException
|
|
5
|
+
from .writer import ClassWriter
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"ClassFile",
|
|
9
|
+
"ClassReader",
|
|
10
|
+
"ClassWriter",
|
|
11
|
+
"FieldInfo",
|
|
12
|
+
"MalformedClassException",
|
|
13
|
+
"MethodInfo",
|
|
14
|
+
]
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
This module implements a single-pass reader that deserialises the binary
|
|
4
4
|
class-file format defined in *The Java Virtual Machine Specification* (JVMS §4)
|
|
5
|
-
into the in-memory ``ClassFile`` structure exposed by :mod:`pytecode.info`.
|
|
5
|
+
into the in-memory ``ClassFile`` structure exposed by :mod:`pytecode.classfile.info`.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import os
|
|
11
11
|
|
|
12
|
+
from .._internal.bytes_utils import BytesReader
|
|
12
13
|
from . import attributes, constant_pool, constants, info, instructions
|
|
13
|
-
from .bytes_utils import BytesReader
|
|
14
14
|
from .modified_utf8 import decode_modified_utf8
|
|
15
15
|
|
|
16
16
|
__all__ = ["ClassReader", "MalformedClassException"]
|
|
@@ -21,7 +21,7 @@ class MalformedClassException(Exception):
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class ClassReader(BytesReader):
|
|
24
|
-
"""Single-pass parser that converts ``.class`` file bytes into a :class:`~pytecode.info.ClassFile` tree.
|
|
24
|
+
"""Single-pass parser that converts ``.class`` file bytes into a :class:`~pytecode.classfile.info.ClassFile` tree.
|
|
25
25
|
|
|
26
26
|
The reader walks the binary layout defined in JVMS §4.1, populating the
|
|
27
27
|
constant pool first (§4.4) and then deserialising fields, methods, and
|
|
@@ -379,7 +379,7 @@ class ClassReader(BytesReader):
|
|
|
379
379
|
"""Read a single ``attribute_info`` structure (JVMS §4.7).
|
|
380
380
|
|
|
381
381
|
Recognised attribute names are decoded into their specific subtypes;
|
|
382
|
-
unknown attributes are returned as :class:`~pytecode.attributes.UnimplementedAttr`.
|
|
382
|
+
unknown attributes are returned as :class:`~pytecode.classfile.attributes.UnimplementedAttr`.
|
|
383
383
|
|
|
384
384
|
Returns:
|
|
385
385
|
The decoded attribute info.
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from .._internal.bytes_utils import BytesWriter
|
|
5
6
|
from . import attributes, constant_pool, instructions
|
|
6
|
-
from .bytes_utils import BytesWriter
|
|
7
7
|
from .info import ClassFile, FieldInfo, MethodInfo
|
|
8
8
|
|
|
9
9
|
__all__ = ["ClassWriter"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Mutable editing models and lowering helpers for JVM class files."""
|
|
2
|
+
|
|
3
|
+
from .constant_pool_builder import ConstantPoolBuilder
|
|
4
|
+
from .model import ClassModel, CodeModel, FieldModel, MethodModel
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"ClassModel",
|
|
8
|
+
"CodeModel",
|
|
9
|
+
"ConstantPoolBuilder",
|
|
10
|
+
"FieldModel",
|
|
11
|
+
"MethodModel",
|
|
12
|
+
]
|
|
@@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, cast
|
|
|
11
11
|
|
|
12
12
|
__all__ = ["ConstantPoolBuilder"]
|
|
13
13
|
|
|
14
|
-
from .constant_pool import (
|
|
14
|
+
from ..classfile.constant_pool import (
|
|
15
15
|
ClassInfo,
|
|
16
16
|
ConstantPoolInfo,
|
|
17
17
|
DoubleInfo,
|
|
@@ -31,7 +31,7 @@ from .constant_pool import (
|
|
|
31
31
|
StringInfo,
|
|
32
32
|
Utf8Info,
|
|
33
33
|
)
|
|
34
|
-
from .modified_utf8 import decode_modified_utf8, encode_modified_utf8
|
|
34
|
+
from ..classfile.modified_utf8 import decode_modified_utf8, encode_modified_utf8
|
|
35
35
|
|
|
36
36
|
if TYPE_CHECKING:
|
|
37
37
|
pass
|
|
@@ -10,7 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
from enum import Enum
|
|
11
11
|
from typing import TYPE_CHECKING, overload
|
|
12
12
|
|
|
13
|
-
from .attributes import AttributeInfo, MethodParametersAttr, SourceDebugExtensionAttr, SourceFileAttr
|
|
13
|
+
from ..classfile.attributes import AttributeInfo, MethodParametersAttr, SourceDebugExtensionAttr, SourceFileAttr
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from .model import ClassModel, CodeModel, MethodModel
|
|
@@ -13,8 +13,7 @@ import copy
|
|
|
13
13
|
from dataclasses import dataclass
|
|
14
14
|
from typing import TYPE_CHECKING, cast
|
|
15
15
|
|
|
16
|
-
from .
|
|
17
|
-
from .attributes import (
|
|
16
|
+
from ..classfile.attributes import (
|
|
18
17
|
AttributeInfo,
|
|
19
18
|
CodeAttr,
|
|
20
19
|
ExceptionInfo,
|
|
@@ -25,11 +24,9 @@ from .attributes import (
|
|
|
25
24
|
LocalVariableTypeInfo,
|
|
26
25
|
LocalVariableTypeTableAttr,
|
|
27
26
|
)
|
|
28
|
-
from .constant_pool import ClassInfo
|
|
29
|
-
from .
|
|
30
|
-
from .
|
|
31
|
-
from .descriptors import parameter_slot_count, parse_method_descriptor
|
|
32
|
-
from .instructions import (
|
|
27
|
+
from ..classfile.constant_pool import ClassInfo
|
|
28
|
+
from ..classfile.descriptors import parameter_slot_count, parse_method_descriptor
|
|
29
|
+
from ..classfile.instructions import (
|
|
33
30
|
Branch,
|
|
34
31
|
BranchW,
|
|
35
32
|
ByteValue,
|
|
@@ -49,6 +46,9 @@ from .instructions import (
|
|
|
49
46
|
ShortValue,
|
|
50
47
|
TableSwitch,
|
|
51
48
|
)
|
|
49
|
+
from ._attribute_clone import clone_attribute
|
|
50
|
+
from .constant_pool_builder import ConstantPoolBuilder
|
|
51
|
+
from .debug_info import DebugInfoPolicy, is_code_debug_info_stale, normalize_debug_info_policy
|
|
52
52
|
from .operands import (
|
|
53
53
|
_BASE_TO_WIDE,
|
|
54
54
|
_VAR_SHORTCUTS,
|
|
@@ -76,7 +76,7 @@ from .operands import (
|
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
if TYPE_CHECKING:
|
|
79
|
-
from .hierarchy import ClassResolver
|
|
79
|
+
from ..analysis.hierarchy import ClassResolver
|
|
80
80
|
from .model import CodeModel, MethodModel
|
|
81
81
|
|
|
82
82
|
|
|
@@ -1093,8 +1093,8 @@ def lower_code(
|
|
|
1093
1093
|
|
|
1094
1094
|
if recompute_frames:
|
|
1095
1095
|
assert method is not None and class_name is not None
|
|
1096
|
-
from
|
|
1097
|
-
from .attributes import StackMapTableAttr
|
|
1096
|
+
from ..analysis import compute_frames
|
|
1097
|
+
from ..classfile.attributes import StackMapTableAttr
|
|
1098
1098
|
|
|
1099
1099
|
frame_result = compute_frames(
|
|
1100
1100
|
code,
|
|
@@ -13,17 +13,14 @@ from typing import TYPE_CHECKING, cast
|
|
|
13
13
|
|
|
14
14
|
__all__ = ["ClassModel", "CodeModel", "FieldModel", "MethodModel"]
|
|
15
15
|
|
|
16
|
-
from .
|
|
17
|
-
from .attributes import (
|
|
16
|
+
from ..classfile.attributes import (
|
|
18
17
|
AttributeInfo,
|
|
19
18
|
CodeAttr,
|
|
20
19
|
LineNumberTableAttr,
|
|
21
20
|
LocalVariableTableAttr,
|
|
22
21
|
LocalVariableTypeTableAttr,
|
|
23
22
|
)
|
|
24
|
-
from .
|
|
25
|
-
from .class_writer import ClassWriter
|
|
26
|
-
from .constant_pool import (
|
|
23
|
+
from ..classfile.constant_pool import (
|
|
27
24
|
ClassInfo,
|
|
28
25
|
DoubleInfo,
|
|
29
26
|
DynamicInfo,
|
|
@@ -39,18 +36,9 @@ from .constant_pool import (
|
|
|
39
36
|
NameAndTypeInfo,
|
|
40
37
|
StringInfo,
|
|
41
38
|
)
|
|
42
|
-
from .
|
|
43
|
-
from .
|
|
44
|
-
from .
|
|
45
|
-
DebugInfoPolicy,
|
|
46
|
-
DebugInfoState,
|
|
47
|
-
is_class_debug_info_stale,
|
|
48
|
-
normalize_debug_info_policy,
|
|
49
|
-
skip_debug_method_attributes,
|
|
50
|
-
strip_class_debug_attributes,
|
|
51
|
-
)
|
|
52
|
-
from .info import ClassFile, FieldInfo, MethodInfo
|
|
53
|
-
from .instructions import (
|
|
39
|
+
from ..classfile.constants import MAGIC, ClassAccessFlag, FieldAccessFlag, MethodAccessFlag
|
|
40
|
+
from ..classfile.info import ClassFile, FieldInfo, MethodInfo
|
|
41
|
+
from ..classfile.instructions import (
|
|
54
42
|
Branch,
|
|
55
43
|
BranchW,
|
|
56
44
|
ConstPoolIndex,
|
|
@@ -66,6 +54,18 @@ from .instructions import (
|
|
|
66
54
|
MultiANewArray,
|
|
67
55
|
TableSwitch,
|
|
68
56
|
)
|
|
57
|
+
from ..classfile.reader import ClassReader
|
|
58
|
+
from ..classfile.writer import ClassWriter
|
|
59
|
+
from ._attribute_clone import clone_attribute, clone_attributes
|
|
60
|
+
from .constant_pool_builder import ConstantPoolBuilder
|
|
61
|
+
from .debug_info import (
|
|
62
|
+
DebugInfoPolicy,
|
|
63
|
+
DebugInfoState,
|
|
64
|
+
is_class_debug_info_stale,
|
|
65
|
+
normalize_debug_info_policy,
|
|
66
|
+
skip_debug_method_attributes,
|
|
67
|
+
strip_class_debug_attributes,
|
|
68
|
+
)
|
|
69
69
|
from .labels import (
|
|
70
70
|
BranchInsn,
|
|
71
71
|
CodeItem,
|
|
@@ -105,7 +105,7 @@ from .operands import (
|
|
|
105
105
|
)
|
|
106
106
|
|
|
107
107
|
if TYPE_CHECKING:
|
|
108
|
-
from .hierarchy import ClassResolver
|
|
108
|
+
from ..analysis.hierarchy import ClassResolver
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
@dataclass
|
|
@@ -16,9 +16,9 @@ from dataclasses import dataclass
|
|
|
16
16
|
from enum import IntFlag
|
|
17
17
|
from typing import Protocol, cast
|
|
18
18
|
|
|
19
|
-
from .constants import ClassAccessFlag, FieldAccessFlag, MethodAccessFlag
|
|
20
|
-
from .descriptors import VoidType, parse_method_descriptor, to_descriptor
|
|
21
|
-
from .model import ClassModel, CodeModel, FieldModel, MethodModel
|
|
19
|
+
from ..classfile.constants import ClassAccessFlag, FieldAccessFlag, MethodAccessFlag
|
|
20
|
+
from ..classfile.descriptors import VoidType, parse_method_descriptor, to_descriptor
|
|
21
|
+
from ..edit.model import ClassModel, CodeModel, FieldModel, MethodModel
|
|
22
22
|
|
|
23
23
|
type Predicate[T] = Callable[[T], bool]
|
|
24
24
|
type ClassPredicate = Predicate[ClassModel]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytecode
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Python library for parsing, manipulating, and emitting JVM class files
|
|
5
5
|
Author: Trenton Smith
|
|
6
6
|
License-Expression: MIT
|
|
@@ -95,8 +95,8 @@ Use `recompute_frames=True` when an edit changes control flow or stack/local lay
|
|
|
95
95
|
|
|
96
96
|
```python
|
|
97
97
|
from pytecode import JarFile
|
|
98
|
-
from pytecode.constants import MethodAccessFlag
|
|
99
|
-
from pytecode.model import ClassModel, MethodModel
|
|
98
|
+
from pytecode.classfile.constants import MethodAccessFlag
|
|
99
|
+
from pytecode.edit.model import ClassModel, MethodModel
|
|
100
100
|
from pytecode.transforms import (
|
|
101
101
|
class_named,
|
|
102
102
|
method_is_public,
|
|
@@ -136,15 +136,15 @@ Top-level exports:
|
|
|
136
136
|
Supported submodules:
|
|
137
137
|
|
|
138
138
|
- `pytecode.transforms` for composable class, field, method, and code transforms.
|
|
139
|
-
- `pytecode.labels` for label-aware bytecode editing helpers.
|
|
140
|
-
- `pytecode.operands` for symbolic operand wrappers.
|
|
139
|
+
- `pytecode.edit.labels` for label-aware bytecode editing helpers.
|
|
140
|
+
- `pytecode.edit.operands` for symbolic operand wrappers.
|
|
141
141
|
- `pytecode.analysis` for CFG construction, frame simulation, and recomputation helpers.
|
|
142
|
-
- `pytecode.verify` for structural validation and diagnostics.
|
|
143
|
-
- `pytecode.hierarchy` for type and override resolution helpers.
|
|
144
|
-
- `pytecode.descriptors` for JVM descriptors and generic signatures.
|
|
145
|
-
- `pytecode.constant_pool_builder` for deterministic constant-pool construction.
|
|
146
|
-
- `pytecode.modified_utf8` for JVM Modified UTF-8 encoding and decoding.
|
|
147
|
-
- `pytecode.debug_info` for explicit debug-info preservation and stripping policies.
|
|
142
|
+
- `pytecode.analysis.verify` for structural validation and diagnostics.
|
|
143
|
+
- `pytecode.analysis.hierarchy` for type and override resolution helpers.
|
|
144
|
+
- `pytecode.classfile.descriptors` for JVM descriptors and generic signatures.
|
|
145
|
+
- `pytecode.edit.constant_pool_builder` for deterministic constant-pool construction.
|
|
146
|
+
- `pytecode.classfile.modified_utf8` for JVM Modified UTF-8 encoding and decoding.
|
|
147
|
+
- `pytecode.edit.debug_info` for explicit debug-info preservation and stripping policies.
|
|
148
148
|
|
|
149
149
|
## Documentation
|
|
150
150
|
|
|
@@ -3,33 +3,36 @@ MANIFEST.in
|
|
|
3
3
|
README.md
|
|
4
4
|
pyproject.toml
|
|
5
5
|
pytecode/__init__.py
|
|
6
|
-
pytecode/_attribute_clone.py
|
|
7
|
-
pytecode/analysis.py
|
|
8
|
-
pytecode/attributes.py
|
|
9
|
-
pytecode/bytes_utils.py
|
|
10
|
-
pytecode/class_reader.py
|
|
11
|
-
pytecode/class_writer.py
|
|
12
|
-
pytecode/constant_pool.py
|
|
13
|
-
pytecode/constant_pool_builder.py
|
|
14
|
-
pytecode/constants.py
|
|
15
|
-
pytecode/debug_info.py
|
|
16
|
-
pytecode/descriptors.py
|
|
17
|
-
pytecode/hierarchy.py
|
|
18
|
-
pytecode/info.py
|
|
19
|
-
pytecode/instructions.py
|
|
20
|
-
pytecode/jar.py
|
|
21
|
-
pytecode/labels.py
|
|
22
|
-
pytecode/model.py
|
|
23
|
-
pytecode/modified_utf8.py
|
|
24
|
-
pytecode/operands.py
|
|
25
6
|
pytecode/py.typed
|
|
26
|
-
pytecode/transforms.py
|
|
27
|
-
pytecode/verify.py
|
|
28
7
|
pytecode.egg-info/PKG-INFO
|
|
29
8
|
pytecode.egg-info/SOURCES.txt
|
|
30
9
|
pytecode.egg-info/dependency_links.txt
|
|
31
10
|
pytecode.egg-info/requires.txt
|
|
32
11
|
pytecode.egg-info/top_level.txt
|
|
12
|
+
pytecode/_internal/__init__.py
|
|
13
|
+
pytecode/_internal/bytes_utils.py
|
|
14
|
+
pytecode/analysis/__init__.py
|
|
15
|
+
pytecode/analysis/hierarchy.py
|
|
16
|
+
pytecode/analysis/verify.py
|
|
17
|
+
pytecode/archive/__init__.py
|
|
18
|
+
pytecode/classfile/__init__.py
|
|
19
|
+
pytecode/classfile/attributes.py
|
|
20
|
+
pytecode/classfile/constant_pool.py
|
|
21
|
+
pytecode/classfile/constants.py
|
|
22
|
+
pytecode/classfile/descriptors.py
|
|
23
|
+
pytecode/classfile/info.py
|
|
24
|
+
pytecode/classfile/instructions.py
|
|
25
|
+
pytecode/classfile/modified_utf8.py
|
|
26
|
+
pytecode/classfile/reader.py
|
|
27
|
+
pytecode/classfile/writer.py
|
|
28
|
+
pytecode/edit/__init__.py
|
|
29
|
+
pytecode/edit/_attribute_clone.py
|
|
30
|
+
pytecode/edit/constant_pool_builder.py
|
|
31
|
+
pytecode/edit/debug_info.py
|
|
32
|
+
pytecode/edit/labels.py
|
|
33
|
+
pytecode/edit/model.py
|
|
34
|
+
pytecode/edit/operands.py
|
|
35
|
+
pytecode/transforms/__init__.py
|
|
33
36
|
tests/test_analysis.py
|
|
34
37
|
tests/test_api_docs.py
|
|
35
38
|
tests/test_attributes.py
|