rapydscript-ns 0.9.2 → 0.9.4
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.
- package/CHANGELOG.md +28 -0
- package/PYTHON_GAPS.md +352 -0
- package/README.md +176 -32
- package/TODO.md +1 -128
- package/bin/rapydscript +70 -70
- package/language-service/index.js +242 -11
- package/memory/project_string_impl.md +43 -0
- package/package.json +1 -1
- package/release/baselib-plain-pretty.js +248 -38
- package/release/baselib-plain-ugly.js +8 -8
- package/release/compiler.js +778 -277
- package/release/signatures.json +30 -30
- package/src/ast.pyj +10 -1
- package/src/baselib-builtins.pyj +56 -2
- package/src/baselib-containers.pyj +25 -1
- package/src/baselib-errors.pyj +7 -3
- package/src/baselib-internal.pyj +51 -6
- package/src/baselib-str.pyj +18 -5
- package/src/lib/asyncio.pyj +534 -0
- package/src/lib/base64.pyj +399 -0
- package/src/lib/bisect.pyj +73 -0
- package/src/lib/collections.pyj +228 -4
- package/src/lib/csv.pyj +494 -0
- package/src/lib/heapq.pyj +98 -0
- package/src/lib/html.pyj +382 -0
- package/src/lib/http/__init__.pyj +98 -0
- package/src/lib/http/client.pyj +304 -0
- package/src/lib/http/cookies.pyj +236 -0
- package/src/lib/logging.pyj +672 -0
- package/src/lib/pprint.pyj +455 -0
- package/src/lib/pythonize.pyj +20 -20
- package/src/lib/statistics.pyj +0 -0
- package/src/lib/string.pyj +357 -0
- package/src/lib/textwrap.pyj +329 -0
- package/src/lib/urllib/__init__.pyj +14 -0
- package/src/lib/urllib/error.pyj +66 -0
- package/src/lib/urllib/parse.pyj +475 -0
- package/src/lib/urllib/request.pyj +86 -0
- package/src/monaco-language-service/analyzer.js +5 -2
- package/src/monaco-language-service/completions.js +26 -0
- package/src/monaco-language-service/diagnostics.js +203 -4
- package/src/monaco-language-service/scope.js +1 -0
- package/src/output/codegen.pyj +4 -1
- package/src/output/functions.pyj +152 -6
- package/src/output/loops.pyj +17 -2
- package/src/output/modules.pyj +1 -1
- package/src/output/operators.pyj +15 -0
- package/src/output/stream.pyj +0 -1
- package/src/parse.pyj +108 -24
- package/src/tokenizer.pyj +19 -3
- package/test/async_generators.pyj +144 -0
- package/test/asyncio.pyj +307 -0
- package/test/base64.pyj +202 -0
- package/test/baselib.pyj +23 -0
- package/test/bisect.pyj +178 -0
- package/test/chainmap.pyj +185 -0
- package/test/csv.pyj +405 -0
- package/test/float_special.pyj +64 -0
- package/test/heapq.pyj +174 -0
- package/test/html.pyj +212 -0
- package/test/http.pyj +259 -0
- package/test/imports.pyj +79 -72
- package/test/logging.pyj +356 -0
- package/test/long.pyj +130 -0
- package/test/parenthesized_with.pyj +141 -0
- package/test/pprint.pyj +232 -0
- package/test/python_compat.pyj +3 -5
- package/test/python_modulo.pyj +76 -0
- package/test/python_modulo_off.pyj +21 -0
- package/test/statistics.pyj +224 -0
- package/test/str.pyj +14 -0
- package/test/string.pyj +245 -0
- package/test/textwrap.pyj +172 -0
- package/test/type_display.pyj +48 -0
- package/test/type_enforcement.pyj +164 -0
- package/test/unit/index.js +94 -6
- package/test/unit/language-service-completions.js +121 -0
- package/test/unit/language-service-scope.js +32 -0
- package/test/unit/language-service.js +190 -5
- package/test/unit/run-language-service.js +17 -3
- package/test/unit/web-repl.js +2401 -13
- package/test/urllib.pyj +193 -0
- package/tools/compile.js +1 -1
- package/tools/embedded_compiler.js +7 -7
- package/tools/export.js +4 -2
- package/web-repl/main.js +1 -1
- package/web-repl/rapydscript.js +7 -5
- package/test/omit_function_metadata.pyj +0 -20
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
###########################################################
|
|
2
|
+
# RapydScript Standard Library
|
|
3
|
+
# urllib.error — Exception classes for urllib
|
|
4
|
+
###########################################################
|
|
5
|
+
#
|
|
6
|
+
# Provides:
|
|
7
|
+
# URLError -- base exception for URL-related errors
|
|
8
|
+
# HTTPError -- raised for HTTP error responses (extends URLError)
|
|
9
|
+
#
|
|
10
|
+
# Usage:
|
|
11
|
+
# from urllib.error import URLError, HTTPError
|
|
12
|
+
#
|
|
13
|
+
# try:
|
|
14
|
+
# resp = await urlopen('https://example.com/missing')
|
|
15
|
+
# except HTTPError as e:
|
|
16
|
+
# print(e.code, e.msg)
|
|
17
|
+
# except URLError as e:
|
|
18
|
+
# print('Network error:', e.reason)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class URLError(Exception):
|
|
22
|
+
"""Exception raised when urlopen() cannot fulfil a request.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
reason -- the error reason (string or exception)
|
|
26
|
+
filename -- the URL that triggered the error, if available
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, reason, filename=None):
|
|
30
|
+
self.reason = reason
|
|
31
|
+
self.filename = filename
|
|
32
|
+
Exception.__init__(self, str(reason))
|
|
33
|
+
|
|
34
|
+
def __str__(self):
|
|
35
|
+
return '<urlopen error ' + str(self.reason) + '>'
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class HTTPError(URLError):
|
|
39
|
+
"""Exception raised for HTTP error responses.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
url -- the URL that triggered the error
|
|
43
|
+
code -- HTTP status code (e.g. 404)
|
|
44
|
+
msg -- HTTP status text (e.g. 'Not Found')
|
|
45
|
+
hdrs -- dict of response headers
|
|
46
|
+
fp -- file-like object for the response body (may be None)
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, url, code, msg, hdrs, fp):
|
|
50
|
+
self.url = url
|
|
51
|
+
self.code = code
|
|
52
|
+
self.msg = msg
|
|
53
|
+
self.hdrs = hdrs
|
|
54
|
+
self.fp = fp
|
|
55
|
+
URLError.__init__(self, msg)
|
|
56
|
+
|
|
57
|
+
def getcode(self):
|
|
58
|
+
"""Return the HTTP status code."""
|
|
59
|
+
return self.code
|
|
60
|
+
|
|
61
|
+
def geturl(self):
|
|
62
|
+
"""Return the URL that triggered the error."""
|
|
63
|
+
return self.url
|
|
64
|
+
|
|
65
|
+
def __str__(self):
|
|
66
|
+
return 'HTTP Error ' + str(self.code) + ': ' + str(self.msg)
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
###########################################################
|
|
2
|
+
# RapydScript Standard Library
|
|
3
|
+
# urllib.parse — URL parsing and encoding utilities
|
|
4
|
+
###########################################################
|
|
5
|
+
#
|
|
6
|
+
# Provides:
|
|
7
|
+
# quote(s[, safe[, encoding[, errors]]]) → percent-encode a string
|
|
8
|
+
# unquote(s[, encoding[, errors]]) → decode %xx sequences
|
|
9
|
+
# quote_plus(s[, safe[, encoding[, errors]]]) → like quote, spaces → '+'
|
|
10
|
+
# unquote_plus(s[, encoding[, errors]]) → like unquote, '+' → space
|
|
11
|
+
# urlencode(query[, doseq]) → encode dict/pairs as query
|
|
12
|
+
# urlsplit(url[, scheme[, allow_fragments]]) → SplitResult
|
|
13
|
+
# urlunsplit(components) → string
|
|
14
|
+
# urlparse(url[, scheme[, allow_fragments]]) → ParseResult
|
|
15
|
+
# urlunparse(components) → string
|
|
16
|
+
# urljoin(base, url[, allow_fragments]) → string
|
|
17
|
+
# parse_qs(qs[, keep_blank_values, ...]) → dict of lists
|
|
18
|
+
# parse_qsl(qs[, keep_blank_values, ...]) → list of [key, value] pairs
|
|
19
|
+
# ParseResult, SplitResult — result classes
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Internal JS helpers
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
v"""
|
|
27
|
+
// -- quote helpers -----------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
// RFC 3986 unreserved characters: A-Z a-z 0-9 - _ . ~
|
|
30
|
+
var _uparse_unreserved = /^[A-Za-z0-9\-_.~]$/;
|
|
31
|
+
|
|
32
|
+
// Characters encodeURIComponent leaves unencoded that Python's quote() encodes.
|
|
33
|
+
// ! * ' ( ) are sub-delimiters; only ~ is truly unreserved and left alone.
|
|
34
|
+
var _uparse_extra = {'!': '%21', "'": '%27', '(': '%28', ')': '%29', '*': '%2A'};
|
|
35
|
+
|
|
36
|
+
// Percent-encode a string. Chars in `safe` and RFC 3986 unreserved chars
|
|
37
|
+
// are left intact; all others are encoded as UTF-8 percent-sequences.
|
|
38
|
+
// Uses Array.from to iterate code points so surrogate pairs encode correctly.
|
|
39
|
+
function _uparse_quote(s, safe) {
|
|
40
|
+
if (safe === null || safe === undefined) safe = '/';
|
|
41
|
+
s = String(s);
|
|
42
|
+
var chars = typeof Array.from === 'function' ? Array.from(s) : s.split('');
|
|
43
|
+
var out = '';
|
|
44
|
+
for (var i = 0; i < chars.length; i++) {
|
|
45
|
+
var c = chars[i];
|
|
46
|
+
if (safe.indexOf(c) >= 0 || _uparse_unreserved.test(c)) {
|
|
47
|
+
out += c;
|
|
48
|
+
} else if (_uparse_extra[c] !== undefined) {
|
|
49
|
+
out += _uparse_extra[c];
|
|
50
|
+
} else {
|
|
51
|
+
out += encodeURIComponent(c);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Decode %xx sequences in a URL component. Tolerates malformed sequences.
|
|
58
|
+
function _uparse_unquote(s) {
|
|
59
|
+
s = String(s);
|
|
60
|
+
return s.replace(/%([0-9A-Fa-f]{2})/g, function(m) {
|
|
61
|
+
try { return decodeURIComponent(m); } catch(e) { return m; }
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// -- urlencode ---------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
function _uparse_urlencode(query, doseq) {
|
|
68
|
+
var pairs = [];
|
|
69
|
+
var items;
|
|
70
|
+
if (Array.isArray(query)) {
|
|
71
|
+
items = query;
|
|
72
|
+
} else if (query && query.jsmap instanceof Map) {
|
|
73
|
+
// ρσ_dict (dict_literals mode)
|
|
74
|
+
items = [];
|
|
75
|
+
query.jsmap.forEach(function(v, k) { items.push([k, v]); });
|
|
76
|
+
} else {
|
|
77
|
+
items = Object.keys(query).map(function(k) { return [k, query[k]]; });
|
|
78
|
+
}
|
|
79
|
+
for (var i = 0; i < items.length; i++) {
|
|
80
|
+
var k = _uparse_quote(String(items[i][0]), '');
|
|
81
|
+
var v = items[i][1];
|
|
82
|
+
if (doseq && Array.isArray(v)) {
|
|
83
|
+
for (var j = 0; j < v.length; j++) {
|
|
84
|
+
pairs.push(k + '=' + _uparse_quote(String(v[j]), ''));
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
pairs.push(k + '=' + _uparse_quote(String(v), ''));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return pairs.join('&');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// -- URL parsing -------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
// RFC 3986 URI-reference regex (Appendix B):
|
|
96
|
+
// ^(scheme:)? (//netloc)? (path) (?query)? (#fragment)?
|
|
97
|
+
var _uparse_URI_RE = /^(?:([a-zA-Z][a-zA-Z0-9+\-.]*):)?(?:\/\/([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?$/;
|
|
98
|
+
|
|
99
|
+
// Parse a URL string into its five RFC 3986 components.
|
|
100
|
+
function _uparse_split(urlstring, scheme) {
|
|
101
|
+
if (!urlstring) return {scheme: '', netloc: '', path: '', query: '', fragment: ''};
|
|
102
|
+
var m = _uparse_URI_RE.exec(urlstring);
|
|
103
|
+
if (!m) return {scheme: '', netloc: '', path: urlstring, query: '', fragment: ''};
|
|
104
|
+
return {
|
|
105
|
+
scheme: m[1] || scheme || '',
|
|
106
|
+
netloc: m[2] !== undefined ? m[2] : '',
|
|
107
|
+
path: m[3] || '',
|
|
108
|
+
query: m[4] !== undefined ? m[4] : '',
|
|
109
|
+
fragment: m[5] !== undefined ? m[5] : ''
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// -- netloc decomposition ---------------------------------------------------
|
|
114
|
+
|
|
115
|
+
// Parse a netloc string into {hostname, port, username, password}.
|
|
116
|
+
// Uses native JS toLowerCase() to avoid relying on String.prototype.lower
|
|
117
|
+
// (which may not be installed in restricted vm contexts).
|
|
118
|
+
function _uparse_netloc_parts(netloc) {
|
|
119
|
+
if (!netloc) return {hostname: null, port: null, username: null, password: null};
|
|
120
|
+
var username = null, password = null;
|
|
121
|
+
var host = netloc;
|
|
122
|
+
var at = netloc.indexOf('@');
|
|
123
|
+
if (at >= 0) {
|
|
124
|
+
var ui = netloc.slice(0, at);
|
|
125
|
+
host = netloc.slice(at + 1);
|
|
126
|
+
var uc = ui.indexOf(':');
|
|
127
|
+
username = uc >= 0 ? ui.slice(0, uc) : ui;
|
|
128
|
+
password = uc >= 0 ? ui.slice(uc + 1) : null;
|
|
129
|
+
}
|
|
130
|
+
var hostname = null, port = null;
|
|
131
|
+
if (host.charAt(0) === '[') {
|
|
132
|
+
// IPv6 bracketed address: [::1] or [::1]:8080
|
|
133
|
+
var eb = host.indexOf(']');
|
|
134
|
+
hostname = eb >= 0 ? host.slice(0, eb + 1).toLowerCase() : host.toLowerCase();
|
|
135
|
+
var after = eb >= 0 ? host.slice(eb + 1) : '';
|
|
136
|
+
if (after.charAt(0) === ':') {
|
|
137
|
+
port = parseInt(after.slice(1), 10);
|
|
138
|
+
if (isNaN(port)) port = null;
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
var lc = host.lastIndexOf(':');
|
|
142
|
+
if (lc >= 0) {
|
|
143
|
+
var maybe_port = parseInt(host.slice(lc + 1), 10);
|
|
144
|
+
if (!isNaN(maybe_port)) {
|
|
145
|
+
hostname = host.slice(0, lc).toLowerCase() || null;
|
|
146
|
+
port = maybe_port;
|
|
147
|
+
} else {
|
|
148
|
+
hostname = host.toLowerCase() || null;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
hostname = host ? host.toLowerCase() : null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return {hostname: hostname, port: port, username: username, password: password};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// -- parse_qsl ---------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
function _uparse_parse_qsl(qs, keep_blank) {
|
|
160
|
+
var result = [];
|
|
161
|
+
if (!qs) return result;
|
|
162
|
+
if (qs.charAt(0) === '?') qs = qs.slice(1);
|
|
163
|
+
var parts = qs.split('&');
|
|
164
|
+
for (var i = 0; i < parts.length; i++) {
|
|
165
|
+
var pair = parts[i];
|
|
166
|
+
if (!pair) continue;
|
|
167
|
+
var idx = pair.indexOf('=');
|
|
168
|
+
var key, val;
|
|
169
|
+
if (idx < 0) {
|
|
170
|
+
key = pair; val = '';
|
|
171
|
+
} else {
|
|
172
|
+
key = pair.slice(0, idx);
|
|
173
|
+
val = pair.slice(idx + 1);
|
|
174
|
+
}
|
|
175
|
+
key = _uparse_unquote(key.split('+').join(' '));
|
|
176
|
+
val = _uparse_unquote(val.split('+').join(' '));
|
|
177
|
+
if (val || keep_blank) result.push([key, val]);
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// -- urljoin -----------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
// Remove RFC 3986 dot segments from a path (Section 5.2.4).
|
|
185
|
+
function _uparse_remove_dots(path) {
|
|
186
|
+
var inp = path, segs = [];
|
|
187
|
+
while (inp.length) {
|
|
188
|
+
if (inp.slice(0, 3) === '../' || inp.slice(0, 2) === './') {
|
|
189
|
+
inp = inp.replace(/^\.\.?\//,'');
|
|
190
|
+
} else if (inp === '/.' || inp.slice(0, 3) === '/./') {
|
|
191
|
+
inp = '/' + inp.slice(inp.charAt(2) === '/' ? 3 : 2);
|
|
192
|
+
} else if (inp === '/..' || inp.slice(0, 4) === '/../') {
|
|
193
|
+
inp = '/' + inp.slice(inp.slice(0, 4) === '/../' ? 4 : 3);
|
|
194
|
+
segs.pop();
|
|
195
|
+
} else if (inp === '.' || inp === '..') {
|
|
196
|
+
inp = '';
|
|
197
|
+
} else {
|
|
198
|
+
var end = inp.indexOf('/', inp.charAt(0) === '/' ? 1 : 0);
|
|
199
|
+
if (end < 0) end = inp.length;
|
|
200
|
+
segs.push(inp.slice(0, end));
|
|
201
|
+
inp = inp.slice(end);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return segs.join('');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Resolve a relative URL against a base URL (RFC 3986 Section 5.2.2).
|
|
208
|
+
// Uses the browser/Node URL constructor when available for correctness,
|
|
209
|
+
// and falls back to the RFC 3986 algorithm in restricted vm contexts.
|
|
210
|
+
var _uparse_URLcls = (function() {
|
|
211
|
+
if (typeof URL !== 'undefined') return URL;
|
|
212
|
+
if (typeof require !== 'undefined') { try { return require('url').URL; } catch(e) {} }
|
|
213
|
+
return null;
|
|
214
|
+
})();
|
|
215
|
+
|
|
216
|
+
function _uparse_urljoin(base, url, allow_fragments) {
|
|
217
|
+
if (_uparse_URLcls) {
|
|
218
|
+
try {
|
|
219
|
+
var u = new _uparse_URLcls(url, base);
|
|
220
|
+
if (!allow_fragments) u.hash = '';
|
|
221
|
+
return u.href;
|
|
222
|
+
} catch(e) {}
|
|
223
|
+
}
|
|
224
|
+
// RFC 3986 Section 5.2.2 reference resolution
|
|
225
|
+
var R = _uparse_split(url, '');
|
|
226
|
+
var B = _uparse_split(base, '');
|
|
227
|
+
var Ts, Tn, Tp, Tq, Tf;
|
|
228
|
+
if (R.scheme) {
|
|
229
|
+
Ts = R.scheme; Tn = R.netloc;
|
|
230
|
+
Tp = _uparse_remove_dots(R.path); Tq = R.query;
|
|
231
|
+
} else {
|
|
232
|
+
if (R.netloc !== '') {
|
|
233
|
+
Tn = R.netloc;
|
|
234
|
+
Tp = _uparse_remove_dots(R.path); Tq = R.query;
|
|
235
|
+
} else {
|
|
236
|
+
if (!R.path) {
|
|
237
|
+
Tp = B.path;
|
|
238
|
+
Tq = R.query !== '' ? R.query : B.query;
|
|
239
|
+
} else {
|
|
240
|
+
if (R.path.charAt(0) === '/') {
|
|
241
|
+
Tp = _uparse_remove_dots(R.path);
|
|
242
|
+
} else {
|
|
243
|
+
var bdir = (B.netloc && !B.path)
|
|
244
|
+
? '/'
|
|
245
|
+
: B.path.slice(0, B.path.lastIndexOf('/') + 1);
|
|
246
|
+
Tp = _uparse_remove_dots(bdir + R.path);
|
|
247
|
+
}
|
|
248
|
+
Tq = R.query;
|
|
249
|
+
}
|
|
250
|
+
Tn = B.netloc;
|
|
251
|
+
}
|
|
252
|
+
Ts = B.scheme;
|
|
253
|
+
}
|
|
254
|
+
Tf = allow_fragments ? R.fragment : '';
|
|
255
|
+
var out = Ts ? Ts + ':' : '';
|
|
256
|
+
if (Tn !== '') out += '//' + Tn;
|
|
257
|
+
out += Tp;
|
|
258
|
+
if (Tq !== '') out += '?' + Tq;
|
|
259
|
+
if (Tf !== '') out += '#' + Tf;
|
|
260
|
+
return out;
|
|
261
|
+
}
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# ---------------------------------------------------------------------------
|
|
266
|
+
# Result classes
|
|
267
|
+
# ---------------------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
class SplitResult:
|
|
270
|
+
"""Result of urlsplit(): scheme, netloc, path, query, fragment."""
|
|
271
|
+
|
|
272
|
+
def __init__(self, scheme, netloc, path, query, fragment):
|
|
273
|
+
self.scheme = scheme
|
|
274
|
+
self.netloc = netloc
|
|
275
|
+
self.path = path
|
|
276
|
+
self.query = query
|
|
277
|
+
self.fragment = fragment
|
|
278
|
+
# Derived auth/host attributes computed via JS helper (avoids
|
|
279
|
+
# relying on String.prototype.lower in restricted vm contexts).
|
|
280
|
+
_auth = _uparse_netloc_parts(netloc)
|
|
281
|
+
self.hostname = _auth['hostname']
|
|
282
|
+
self.port = _auth['port']
|
|
283
|
+
self.username = _auth['username']
|
|
284
|
+
self.password = _auth['password']
|
|
285
|
+
|
|
286
|
+
def geturl(self):
|
|
287
|
+
"""Reconstruct the original URL from its components."""
|
|
288
|
+
return urlunsplit((self.scheme, self.netloc, self.path, self.query, self.fragment))
|
|
289
|
+
|
|
290
|
+
def __repr__(self):
|
|
291
|
+
return ('SplitResult(scheme=' + repr(self.scheme) +
|
|
292
|
+
', netloc=' + repr(self.netloc) +
|
|
293
|
+
', path=' + repr(self.path) +
|
|
294
|
+
', query=' + repr(self.query) +
|
|
295
|
+
', fragment=' + repr(self.fragment) + ')')
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class ParseResult:
|
|
299
|
+
"""Result of urlparse(): scheme, netloc, path, params, query, fragment."""
|
|
300
|
+
|
|
301
|
+
def __init__(self, scheme, netloc, path, params, query, fragment):
|
|
302
|
+
self.scheme = scheme
|
|
303
|
+
self.netloc = netloc
|
|
304
|
+
self.path = path
|
|
305
|
+
self.params = params
|
|
306
|
+
self.query = query
|
|
307
|
+
self.fragment = fragment
|
|
308
|
+
# Derived auth/host attributes computed via JS helper (avoids
|
|
309
|
+
# relying on String.prototype.lower in restricted vm contexts).
|
|
310
|
+
_auth = _uparse_netloc_parts(netloc)
|
|
311
|
+
self.hostname = _auth['hostname']
|
|
312
|
+
self.port = _auth['port']
|
|
313
|
+
self.username = _auth['username']
|
|
314
|
+
self.password = _auth['password']
|
|
315
|
+
|
|
316
|
+
def geturl(self):
|
|
317
|
+
"""Reconstruct the original URL from its components."""
|
|
318
|
+
return urlunparse((self.scheme, self.netloc, self.path, self.params, self.query, self.fragment))
|
|
319
|
+
|
|
320
|
+
def __repr__(self):
|
|
321
|
+
return ('ParseResult(scheme=' + repr(self.scheme) +
|
|
322
|
+
', netloc=' + repr(self.netloc) +
|
|
323
|
+
', path=' + repr(self.path) +
|
|
324
|
+
', params=' + repr(self.params) +
|
|
325
|
+
', query=' + repr(self.query) +
|
|
326
|
+
', fragment=' + repr(self.fragment) + ')')
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
# ---------------------------------------------------------------------------
|
|
330
|
+
# Public API
|
|
331
|
+
# ---------------------------------------------------------------------------
|
|
332
|
+
|
|
333
|
+
def quote(string, safe='/', encoding=None, errors=None):
|
|
334
|
+
"""Percent-encode a string for safe inclusion in a URL.
|
|
335
|
+
|
|
336
|
+
Characters listed in safe (default '/') and RFC 3986 unreserved characters
|
|
337
|
+
(A-Z, a-z, 0-9, -, _, ., ~) are never encoded. All other characters are
|
|
338
|
+
encoded as UTF-8 percent-sequences.
|
|
339
|
+
"""
|
|
340
|
+
return _uparse_quote(string, safe)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def unquote(string, encoding='utf-8', errors='replace'):
|
|
344
|
+
"""Decode percent-encoded sequences (%xx) in a URL component.
|
|
345
|
+
|
|
346
|
+
'+' signs are NOT decoded as spaces; use unquote_plus() for that.
|
|
347
|
+
"""
|
|
348
|
+
return _uparse_unquote(string)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def quote_plus(string, safe='', encoding=None, errors=None):
|
|
352
|
+
"""Like quote(), but spaces are encoded as '+' instead of '%20'."""
|
|
353
|
+
v"""return _uparse_quote(string, safe).split('%20').join('+');"""
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def unquote_plus(string, encoding='utf-8', errors='replace'):
|
|
357
|
+
"""Like unquote(), but '+' signs are decoded as spaces first."""
|
|
358
|
+
v"""return _uparse_unquote(string.split('+').join(' '));"""
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def urlencode(query, doseq=False):
|
|
362
|
+
"""Encode a mapping or sequence of pairs as a URL query string.
|
|
363
|
+
|
|
364
|
+
query may be a dict or a list of [key, value] pairs.
|
|
365
|
+
When doseq=True, values that are sequences are expanded into separate pairs.
|
|
366
|
+
"""
|
|
367
|
+
return _uparse_urlencode(query, doseq)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def urlsplit(urlstring, scheme='', allow_fragments=True):
|
|
371
|
+
"""Parse a URL into (scheme, netloc, path, query, fragment).
|
|
372
|
+
|
|
373
|
+
Returns a SplitResult. Unlike urlparse(), the path component is not
|
|
374
|
+
split on ';' — params remain part of path.
|
|
375
|
+
"""
|
|
376
|
+
parts = _uparse_split(urlstring, scheme)
|
|
377
|
+
_scheme = parts['scheme']
|
|
378
|
+
_netloc = parts['netloc']
|
|
379
|
+
_path = parts['path']
|
|
380
|
+
_query = parts['query']
|
|
381
|
+
_frag = parts['fragment']
|
|
382
|
+
if not allow_fragments and _frag:
|
|
383
|
+
_query = _query + '#' + _frag
|
|
384
|
+
_frag = ''
|
|
385
|
+
return SplitResult(_scheme, _netloc, _path, _query, _frag)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def urlunsplit(components):
|
|
389
|
+
"""Combine the elements of a SplitResult (or 5-tuple) back into a URL string.
|
|
390
|
+
|
|
391
|
+
components = (scheme, netloc, path, query, fragment)
|
|
392
|
+
"""
|
|
393
|
+
scheme = components[0]
|
|
394
|
+
netloc = components[1]
|
|
395
|
+
path = components[2]
|
|
396
|
+
query = components[3]
|
|
397
|
+
fragment = components[4]
|
|
398
|
+
url = path
|
|
399
|
+
if netloc:
|
|
400
|
+
if url and v'url.charAt(0) !== "/"':
|
|
401
|
+
url = '/' + url
|
|
402
|
+
url = '//' + netloc + url
|
|
403
|
+
if scheme:
|
|
404
|
+
url = scheme + ':' + url
|
|
405
|
+
if query:
|
|
406
|
+
url = url + '?' + query
|
|
407
|
+
if fragment:
|
|
408
|
+
url = url + '#' + fragment
|
|
409
|
+
return url
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def urlparse(urlstring, scheme='', allow_fragments=True):
|
|
413
|
+
"""Parse a URL into (scheme, netloc, path, params, query, fragment).
|
|
414
|
+
|
|
415
|
+
Returns a ParseResult. params is the text after the first ';' in the
|
|
416
|
+
path (used in FTP-style URLs such as ftp://host/path;type=a).
|
|
417
|
+
"""
|
|
418
|
+
sr = urlsplit(urlstring, scheme, allow_fragments)
|
|
419
|
+
path = sr.path
|
|
420
|
+
params = ''
|
|
421
|
+
semi = v'path.indexOf(";")'
|
|
422
|
+
if semi >= 0:
|
|
423
|
+
params = v'path.slice(semi + 1)'
|
|
424
|
+
path = v'path.slice(0, semi)'
|
|
425
|
+
return ParseResult(sr.scheme, sr.netloc, path, params, sr.query, sr.fragment)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def urlunparse(components):
|
|
429
|
+
"""Combine the elements of a ParseResult (or 6-tuple) back into a URL string.
|
|
430
|
+
|
|
431
|
+
components = (scheme, netloc, path, params, query, fragment)
|
|
432
|
+
"""
|
|
433
|
+
scheme = components[0]
|
|
434
|
+
netloc = components[1]
|
|
435
|
+
path = components[2]
|
|
436
|
+
params = components[3]
|
|
437
|
+
query = components[4]
|
|
438
|
+
fragment = components[5]
|
|
439
|
+
if params:
|
|
440
|
+
path = path + ';' + params
|
|
441
|
+
return urlunsplit((scheme, netloc, path, query, fragment))
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def urljoin(base, url, allow_fragments=True):
|
|
445
|
+
"""Resolve a possibly relative URL against a base URL.
|
|
446
|
+
|
|
447
|
+
Returns the absolute URL that results from joining base and url.
|
|
448
|
+
"""
|
|
449
|
+
return _uparse_urljoin(base, url, allow_fragments)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
|
|
453
|
+
encoding='utf-8', errors='replace', max_num_fields=None):
|
|
454
|
+
"""Parse a query string into a list of (name, value) pairs.
|
|
455
|
+
|
|
456
|
+
keep_blank_values controls whether entries with empty values are returned.
|
|
457
|
+
"""
|
|
458
|
+
return _uparse_parse_qsl(qs, keep_blank_values)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
|
|
462
|
+
encoding='utf-8', errors='replace', max_num_fields=None):
|
|
463
|
+
"""Parse a query string into a dict mapping names to lists of values.
|
|
464
|
+
|
|
465
|
+
Values in the returned dict are always lists (even for single occurrences).
|
|
466
|
+
"""
|
|
467
|
+
d = {}
|
|
468
|
+
for pair in _uparse_parse_qsl(qs, keep_blank_values):
|
|
469
|
+
k = pair[0]
|
|
470
|
+
v = pair[1]
|
|
471
|
+
if k in d:
|
|
472
|
+
d[k].append(v)
|
|
473
|
+
else:
|
|
474
|
+
d[k] = [v]
|
|
475
|
+
return d
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
###########################################################
|
|
2
|
+
# RapydScript Standard Library
|
|
3
|
+
# urllib.request — HTTP requests via the Fetch API
|
|
4
|
+
###########################################################
|
|
5
|
+
#
|
|
6
|
+
# Provides:
|
|
7
|
+
# urlopen(url[, data[, timeout]]) — open a URL; returns a Promise
|
|
8
|
+
#
|
|
9
|
+
# Usage (inside an async function):
|
|
10
|
+
# from urllib.request import urlopen
|
|
11
|
+
#
|
|
12
|
+
# async def fetch_json(url):
|
|
13
|
+
# resp = await urlopen(url)
|
|
14
|
+
# data = await resp.json()
|
|
15
|
+
# return data
|
|
16
|
+
#
|
|
17
|
+
# The response object exposes:
|
|
18
|
+
# .status -- HTTP status code (int)
|
|
19
|
+
# .reason -- HTTP status text (str)
|
|
20
|
+
# .url -- final URL after any redirects (str)
|
|
21
|
+
# .headers -- plain dict of lowercase header names → values
|
|
22
|
+
# .read() -- Promise → response body as a string
|
|
23
|
+
# .json() -- Promise → parsed JSON response body
|
|
24
|
+
# .close() -- no-op (for API compatibility)
|
|
25
|
+
#
|
|
26
|
+
# Raises urllib.error.HTTPError for non-2xx responses.
|
|
27
|
+
# Raises urllib.error.URLError for network/timeout failures.
|
|
28
|
+
#
|
|
29
|
+
# Note: urlopen() wraps the browser/Node Fetch API and therefore returns a
|
|
30
|
+
# Promise. It must be awaited inside an async function. There is no
|
|
31
|
+
# synchronous version because JavaScript has no synchronous HTTP.
|
|
32
|
+
|
|
33
|
+
from urllib.error import URLError, HTTPError
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def urlopen(url, data=None, timeout=None):
|
|
37
|
+
"""Open url, returning a Promise that resolves to a response object.
|
|
38
|
+
|
|
39
|
+
url -- the URL to open (string)
|
|
40
|
+
data -- if given, the request uses POST and sends data as the body
|
|
41
|
+
timeout -- seconds before an AbortController cancels the request (float)
|
|
42
|
+
|
|
43
|
+
On success the Promise resolves to an object with .status, .reason, .url,
|
|
44
|
+
.headers, .read(), .json(), and .close() (see module docstring).
|
|
45
|
+
On HTTP error (non-2xx status) the Promise rejects with HTTPError.
|
|
46
|
+
On network failure the Promise rejects with URLError.
|
|
47
|
+
"""
|
|
48
|
+
v"""
|
|
49
|
+
var _opts = { method: data != null ? 'POST' : 'GET' };
|
|
50
|
+
if (data != null) {
|
|
51
|
+
_opts.body = data;
|
|
52
|
+
_opts.headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
|
53
|
+
}
|
|
54
|
+
var _abort = null;
|
|
55
|
+
if (timeout != null && typeof AbortController !== 'undefined') {
|
|
56
|
+
var _ctrl = new AbortController();
|
|
57
|
+
_opts.signal = _ctrl.signal;
|
|
58
|
+
_abort = setTimeout(function() { _ctrl.abort(); }, timeout * 1000);
|
|
59
|
+
}
|
|
60
|
+
return Promise.resolve()
|
|
61
|
+
.then(function() { return fetch(url, _opts); })
|
|
62
|
+
.then(function(resp) {
|
|
63
|
+
if (_abort) { clearTimeout(_abort); _abort = null; }
|
|
64
|
+
var hdrs = {};
|
|
65
|
+
if (resp.headers && typeof resp.headers.forEach === 'function') {
|
|
66
|
+
resp.headers.forEach(function(v, k) { hdrs[k] = v; });
|
|
67
|
+
}
|
|
68
|
+
if (!resp.ok) {
|
|
69
|
+
throw new HTTPError(resp.url, resp.status, resp.statusText, hdrs, null);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
status: resp.status,
|
|
73
|
+
reason: resp.statusText,
|
|
74
|
+
url: resp.url,
|
|
75
|
+
headers: hdrs,
|
|
76
|
+
read: function() { return resp.text(); },
|
|
77
|
+
json: function() { return resp.json(); },
|
|
78
|
+
close: function() {}
|
|
79
|
+
};
|
|
80
|
+
})
|
|
81
|
+
.catch(function(e) {
|
|
82
|
+
if (_abort) { clearTimeout(_abort); _abort = null; }
|
|
83
|
+
if (e instanceof HTTPError) throw e;
|
|
84
|
+
throw new URLError(String(e));
|
|
85
|
+
});
|
|
86
|
+
"""
|
|
@@ -236,6 +236,7 @@ class ScopeBuilder {
|
|
|
236
236
|
return_type: opts.return_type || null,
|
|
237
237
|
source_module: opts.source_module || null,
|
|
238
238
|
original_name: opts.original_name || null,
|
|
239
|
+
is_bare_import: opts.is_bare_import || false,
|
|
239
240
|
});
|
|
240
241
|
scope.addSymbol(sym);
|
|
241
242
|
return sym;
|
|
@@ -362,8 +363,10 @@ class ScopeBuilder {
|
|
|
362
363
|
if (name) {
|
|
363
364
|
this._add_symbol({
|
|
364
365
|
name,
|
|
365
|
-
kind:
|
|
366
|
-
defined_at:
|
|
366
|
+
kind: 'import',
|
|
367
|
+
defined_at: pos_from_token(node.start),
|
|
368
|
+
source_module: node.key || null,
|
|
369
|
+
is_bare_import: true,
|
|
367
370
|
});
|
|
368
371
|
}
|
|
369
372
|
|
|
@@ -523,6 +523,32 @@ export class CompletionEngine {
|
|
|
523
523
|
}
|
|
524
524
|
}
|
|
525
525
|
|
|
526
|
+
// 1.1. Module member completions — `import X; X.attr`
|
|
527
|
+
// When the symbol is a bare import, parse the module source and
|
|
528
|
+
// expose its top-level symbols as dot-completions.
|
|
529
|
+
if (!scope_matched && obj_sym && obj_sym.is_bare_import && obj_sym.source_module) {
|
|
530
|
+
const mod_src = this._virtualFiles[obj_sym.source_module]
|
|
531
|
+
|| this._stdlibFiles[obj_sym.source_module];
|
|
532
|
+
if (mod_src) {
|
|
533
|
+
let mod_map;
|
|
534
|
+
try { mod_map = this._analyzer.analyze(mod_src, {}); } catch (_e) { /* ignore */ }
|
|
535
|
+
if (mod_map) {
|
|
536
|
+
const mod_frame = mod_map.frames.find(f => f.kind === 'module');
|
|
537
|
+
if (mod_frame) {
|
|
538
|
+
scope_matched = true;
|
|
539
|
+
for (const [name, sym] of mod_frame.symbols) {
|
|
540
|
+
if (!ctx.prefix || name.startsWith(ctx.prefix)) {
|
|
541
|
+
if (!seen.has(name)) {
|
|
542
|
+
seen.add(name);
|
|
543
|
+
items.push(symbol_to_item(sym, range, monacoKind, '0'));
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
526
552
|
// 1.5. Built-in type members — list, str, dict, number.
|
|
527
553
|
// Used when inferred_class names a built-in type, not a user class.
|
|
528
554
|
if (!scope_matched && this._builtins && obj_sym && obj_sym.inferred_class) {
|