forked from pyodide/pyodide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpyodide.py
124 lines (100 loc) · 2.88 KB
/
pyodide.py
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
"""
A library of helper utilities for connecting Python to the browser environment.
"""
import ast
import io
from textwrap import dedent
__version__ = '0.14.0'
def open_url(url):
"""
Fetches a given *url* and returns a io.StringIO to access its contents.
"""
from js import XMLHttpRequest
req = XMLHttpRequest.new()
req.open('GET', url, False)
req.send(None)
return io.StringIO(req.response)
def eval_code(code, ns):
"""
Runs a string of code, the last part of which may be an expression.
"""
# handle mis-indented input from multi-line strings
code = dedent(code)
mod = ast.parse(code)
if len(mod.body) == 0:
return None
if isinstance(mod.body[-1], ast.Expr):
expr = ast.Expression(mod.body[-1].value)
del mod.body[-1]
else:
expr = None
if len(mod.body):
exec(compile(mod, '<exec>', mode='exec'), ns, ns)
if expr is not None:
return eval(compile(expr, '<eval>', mode='eval'), ns, ns)
else:
return None
def find_imports(code):
"""
Finds the imports in a string of code and returns a list of their package
names.
"""
# handle mis-indented input from multi-line strings
code = dedent(code)
mod = ast.parse(code)
imports = set()
for node in ast.walk(mod):
if isinstance(node, ast.Import):
for name in node.names:
name = name.name
imports.add(name.split('.')[0])
elif isinstance(node, ast.ImportFrom):
name = node.module
imports.add(name.split('.')[0])
return list(imports)
def as_nested_list(obj):
"""
Assumes a Javascript object is made of (possibly nested) arrays and
converts them to nested Python lists.
"""
try:
it = iter(obj)
return [as_nested_list(x) for x in it]
except TypeError:
return obj
def get_completions(code, cursor=None):
"""
Get code autocompletion candidates.
Follows the completion API in Jupyter outlined here:
https://jupyter-client.readthedocs.io/en/stable/messaging.html#completion
"""
import jedi
if cursor is None:
cursor = len(code)
code = code[:cursor]
interp = jedi.Interpreter(source=code, namespaces=[globals()])
completions = interp.completions()
if len(completions) == 0:
return {
'matches': [],
'cursor_start': cursor,
'cursor_end': cursor,
'metadata': {},
'status': 'ok'
}
c = completions[0]
delta = len(c.name_with_symbols) - len(c.complete)
return {
'matches': [x.full_name for x in completions],
'cursor_start': cursor - delta,
'cursor_end': cursor,
'metadata': {},
'status': 'ok'
}
__all__ = [
'open_url',
'eval_code',
'find_imports',
'as_nested_list',
'get_completions'
]