Skip to content

Commit 55e97af

Browse files
authored
Merge pull request #2054 from BolunThompson/str_dis
Change dis.dis to take strings to decompile
2 parents 8dccb60 + 5ecb288 commit 55e97af

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

Lib/test/test_dis.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import subprocess
2+
import sys
3+
import unittest
4+
5+
# This only tests that it prints something in order
6+
# to avoid changing this test if the bytecode changes
7+
8+
# These tests start a new process instead of redirecting stdout because
9+
# stdout is being written to by rust code, which currently can't be
10+
# redirected by reassigning sys.stdout
11+
12+
13+
class TestDis(unittest.TestCase):
14+
@classmethod
15+
def setUpClass(cls):
16+
cls.setup = """
17+
import dis
18+
def tested_func(): pass
19+
"""
20+
cls.command = (sys.executable, "-c")
21+
22+
def test_dis(self):
23+
test_code = f"""
24+
{self.setup}
25+
dis.dis(tested_func)
26+
dis.dis("x = 2; print(x)")
27+
"""
28+
29+
result = subprocess.run(
30+
self.command + (test_code,), capture_output=True
31+
)
32+
self.assertNotEqual("", result.stdout.decode())
33+
self.assertEqual("", result.stderr.decode())
34+
35+
def test_disassemble(self):
36+
test_code = f"""
37+
{self.setup}
38+
dis.disassemble(tested_func)
39+
"""
40+
result = subprocess.run(
41+
self.command + (test_code,), capture_output=True
42+
)
43+
# In CPython this would raise an AttributeError, not a
44+
# TypeError because dis is implemented in python in CPython and
45+
# as such the type mismatch wouldn't be caught immeadiately
46+
self.assertIn("TypeError", result.stderr.decode())
47+
48+
test_code = f"""
49+
{self.setup}
50+
dis.disassemble(tested_func.__code__)
51+
"""
52+
result = subprocess.run(
53+
self.command + (test_code,), capture_output=True
54+
)
55+
self.assertNotEqual("", result.stdout.decode())
56+
self.assertEqual("", result.stderr.decode())
57+
58+
59+
if __name__ == "__main__":
60+
unittest.main()

vm/src/stdlib/dis.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
use crate::bytecode::CodeFlags;
22
use crate::obj::objcode::PyCodeRef;
3+
use crate::obj::objstr::PyStringRef;
34
use crate::pyobject::{ItemProtocol, PyObjectRef, PyResult, TryFromObject};
45
use crate::vm::VirtualMachine;
6+
use rustpython_compiler::compile;
57

68
fn dis_dis(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
79
// Method or function:
810
if let Ok(co) = vm.get_attribute(obj.clone(), "__code__") {
911
return dis_disassemble(co, vm);
1012
}
1113

14+
// String:
15+
if let Ok(co_str) = PyStringRef::try_from_object(vm, obj.clone()) {
16+
let code = vm
17+
.compile(co_str.as_str(), compile::Mode::Exec, "<string>".to_owned())
18+
.map_err(|err| vm.new_syntax_error(&err))?
19+
.into_object();
20+
return dis_disassemble(code, vm);
21+
}
22+
1223
dis_disassemble(obj, vm)
1324
}
1425

0 commit comments

Comments
 (0)