forked from adafruit/circuitpython
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathimport_mpy_native.py
More file actions
130 lines (101 loc) · 3.39 KB
/
Copy pathimport_mpy_native.py
File metadata and controls
130 lines (101 loc) · 3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# test importing of .mpy files with native code
try:
import sys, io, vfs
sys.implementation._mpy
io.IOBase
except (ImportError, AttributeError):
print("SKIP")
raise SystemExit
mpy_arch = sys.implementation._mpy >> 8
if mpy_arch >> 2 == 0:
# This system does not support .mpy files containing native code
print("SKIP")
raise SystemExit
class UserFile(io.IOBase):
def __init__(self, data):
self.data = memoryview(data)
self.pos = 0
def readinto(self, buf):
n = min(len(buf), len(self.data) - self.pos)
buf[:n] = self.data[self.pos : self.pos + n]
self.pos += n
return n
def ioctl(self, req, arg):
if req == 4: # MP_STREAM_CLOSE
return 0
return -1
class UserFS:
def __init__(self, files):
self.files = files
def mount(self, readonly, mksfs):
pass
def umount(self):
pass
def stat(self, path):
if path in self.files:
return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0)
raise OSError
def open(self, path, mode):
return UserFile(self.files[path])
# these are the test .mpy files
# CIRCUITPY-CHANGE
valid_header = bytes([ord("C"), 6, mpy_arch, 31])
# fmt: off
user_files = {
# bad architecture (mpy_arch needed for sub-version)
# CIRCUITPY-CHANGE
'/mod0.mpy': bytes([ord('C'), 6, 0xfc | mpy_arch, 31]),
# test loading of viper and asm
'/mod1.mpy': valid_header + (
b'\x02' # n_qstr
b'\x00' # n_obj
b'\x0emod1.py\x00' # qstr0 = "mod1.py"
b'\x0aouter\x00' # qstr1 = "outer"
b'\x2c' # 5 bytes, have children, bytecode
b'\x00\x02' # prelude
b'\x01' # simple name (qstr index)
b'\x51' # LOAD_CONST_NONE
b'\x63' # RETURN_VALUE
b'\x02' # 2 children
b'\x42' # 8 bytes, no children, viper code
b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code
b'\x00' # scope_flags
b'\x43' # 8 bytes, no children, asm code
b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code
b'\x00\x00\x00' # scope_flags, n_pos_args, type_sig
),
# test loading viper with additional scope flags and relocation
'/mod2.mpy': valid_header + (
b'\x02' # n_qstr
b'\x00' # n_obj
b'\x0emod2.py\x00' # qstr0 = "mod2.py"
b'\x0aouter\x00' # qstr1 = "outer"
b'\x2c' # 5 bytes, have children, bytecode
b'\x00\x02' # prelude
b'\x01' # simple name (qstr index)
b'\x51' # LOAD_CONST_NONE
b'\x63' # RETURN_VALUE
b'\x01' # 1 child
b'\x22' # 4 bytes, no children, viper code
b'\x00\x00\x00\x00' # dummy machine code
b'\x70' # scope_flags: VIPERBSS | VIPERRODATA | VIPERRELOC
b'\x06\x04' # rodata=6 bytes, bss=4 bytes
b'rodata' # rodata content
b'\x03\x01\x00' # dummy relocation of rodata
),
}
# fmt: on
# create and mount a user filesystem
vfs.mount(UserFS(user_files), "/userfs")
sys.path.append("/userfs")
# import .mpy files from the user filesystem
for i in range(len(user_files)):
mod = "mod%u" % i
try:
__import__(mod)
print(mod, "OK")
except ValueError as er:
print(mod, "ValueError", er)
# unmount and undo path addition
vfs.umount("/userfs")
sys.path.pop()