forked from Submersible/node-python-bridge
- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnode_python_bridge.py
More file actions
Latest commit
122 lines (104 loc) · 3.66 KB
/
Copy pathnode_python_bridge.py
File metadata and controls
122 lines (104 loc) · 3.66 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
from __future__ importunicode_literals
fromcodeopimportCompile
importos
importsys
importjson
importtraceback
importplatform
importstruct
importmath
NODE_CHANNEL_FD=int(os.environ['NODE_CHANNEL_FD'])
UNICODE_TYPE=unicodeifsys.version_info[0] ==2elsestr
ifsys.version_info[0] <=2:
# print('PY2')
def_exec(_code_, _globs_):
exec('exec _code_ in _globs_')
else:
_exec=getattr(__builtins__, 'exec')
_locals= {'__name__': '__console__', '__doc__': None}
_compile=Compile()
ifplatform.system() =='Windows':
# hacky reimplementation of https://github.com/nodejs/node/blob/master/deps/uv/src/win/pipe.c
defread_data(f):
header=f.read(16)
ifnotheader:
returnheader
try:
msg_length, =struct.unpack('<Q', header[8:])
returnf.read(msg_length)
except:
raiseValueError('Error parsing msg with header: {}'.format(repr(header)))
defwrite_data(f, data):
header=struct.pack('<Q', 1) +struct.pack('<Q', len(data))
f.write(header+data)
f.flush()
else:
defread_data(f):
returnreader.readline()
defwrite_data(f, data):
f.write(data)
f.flush()
defformat_exception(t=None, e=None, tb=None):
returndict(
exception=dict(
type=dict(
name=t.__name__,
module=t.__module__
) iftelseNone,
message=str(e),
args=getattr(e, 'args', None),
format=traceback.format_exception_only(t, e)
) ifeelseNone,
traceback=dict(
lineno=traceback.tb_lineno(tb) ifhasattr(traceback, 'tb_lineno') elsetb.tb_lineno,
strack=traceback.format_stack(tb.tb_frame),
format=traceback.format_tb(tb)
) iftbelseNone,
format=traceback.format_exception(t, e, tb)
)
classJavaScriptEncoder(json.JSONEncoder):
defdefault(self, o):
ifmath.isnan(o):
return'NaN'
ifmath.isinf(o):
return'Infinity'ifo>0else'-Infinity'
returno.__dict__
if__name__=='__main__':
writer=os.fdopen(NODE_CHANNEL_FD, 'wb')
reader=os.fdopen(NODE_CHANNEL_FD, 'rb')
whileTrue:
try:
# Read new command
line=read_data(reader)
ifnotline:
break
try:
data=json.loads(line.decode('utf-8'))
exceptValueError:
raiseValueError('Could not decode IPC data:\n{}'.format(repr(line)))
# Assert data saneness
ifdata['type'] notin ['execute', 'evaluate']:
raiseException('Python bridge call `type` must be `execute` or `evaluate`')
ifnotisinstance(data['code'], UNICODE_TYPE):
raiseException('Python bridge call `code` must be a string.')
# Run Python code
ifdata['type'] =='execute':
_exec(_compile(data['code'], '<input>', 'exec'), _locals)
response=dict(type='success')
else:
value=eval(_compile(data['code'], '<input>', 'eval'), _locals)
response=dict(type='success', value=json.dumps(value, separators=(',', ':'), cls=JavaScriptEncoder))
except:
t, e, tb=sys.exc_info()
response=dict(type='exception', value=format_exception(t, e, tb))
data=json.dumps(response, separators=(',', ':')).encode('utf-8') +b'\n'
write_data(writer, data)
# Closing is messy
try:
reader.close()
exceptIOError:
pass
try:
writer.close()
exceptIOError:
pass