rapydscript-ns 0.9.0 → 0.9.1

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "rapydscript-ns",
3
3
  "description": "Pythonic JavaScript that doesn't suck",
4
4
  "homepage": "https://github.com/ficocelliguy/rapydscript-ns",
5
- "version": "0.9.0",
5
+ "version": "0.9.1",
6
6
  "license": "BSD-2-Clause",
7
7
  "engines": {
8
8
  "node": ">=0.12.0"
@@ -15126,7 +15126,7 @@ return this.__repr__();
15126
15126
  WHITESPACE_CHARS = make_predicate(characters("  \n\r\t\f\u000b​᠎           \u202f  "));
15127
15127
  PUNC_BEFORE_EXPRESSION = make_predicate(characters("[{(,.;:"));
15128
15128
  PUNC_CHARS = make_predicate(characters("[]{}(),;:?"));
15129
- KEYWORDS = "as assert async await break class continue def del do elif else except finally for from global if import in is lambda new nonlocal pass raise return yield try while with or and not";
15129
+ KEYWORDS = "as assert async await break class continue debugger def del do elif else except finally for from global if import in is lambda new nonlocal pass raise return yield try while with or and not";
15130
15130
  KEYWORDS_ATOM = "False None True";
15131
15131
  RESERVED_WORDS = "break case class catch const continue debugger default delete do else export extends finally for function if import in instanceof new return switch this throw try typeof var void while with yield implements static private package let public protected interface await null true false";
15132
15132
  KEYWORDS_BEFORE_EXPRESSION = "return yield new del raise elif else if";
@@ -16244,7 +16244,7 @@ return this.__repr__();
16244
16244
  var is_token = ρσ_modules.tokenizer.is_token;
16245
16245
  var RESERVED_WORDS = ρσ_modules.tokenizer.RESERVED_WORDS;
16246
16246
 
16247
- COMPILER_VERSION = "fd346949151ce69268600b19489d22e404377c38";
16247
+ COMPILER_VERSION = "146ab479438eea3efe2870440ee9a4ef2bdd4319";
16248
16248
  PYTHON_FLAGS = (function(){
16249
16249
  var ρσ_d = Object.create(null);
16250
16250
  ρσ_d["dict_literals"] = true;
@@ -26,9 +26,9 @@
26
26
  "output/utils": "595968f96f6fdcc51eb41c34d64c92bb595e3cb1",
27
27
  "parse": "0643834ed3c98d350ceb9ec71179f8923974c08c",
28
28
  "string_interpolation": "bff1cc76d772d24d35707f6c794f38734ca08376",
29
- "tokenizer": "134f46d5a10576c6a27d4fe024c63f45e111fefe",
29
+ "tokenizer": "79cf9d42ec2613b409b4dc6ed0e3ce112e4bd8c0",
30
30
  "unicode_aliases": "79ac6eaa5e6be44a5397d62c561f854a8fe7528e",
31
31
  "utils": "c1666db819aa7c8db38697e34e18362e3cb45869",
32
- "#compiler#": "d41c267ea92de4937495c7d35c8d50e1b48f550c",
33
- "#compiled_with#": "d41c267ea92de4937495c7d35c8d50e1b48f550c"
32
+ "#compiler#": "fb53a74e155394a3b3834df62d3bbb2778d92ea7",
33
+ "#compiled_with#": "fb53a74e155394a3b3834df62d3bbb2778d92ea7"
34
34
  }
@@ -0,0 +1,379 @@
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD
3
+ # RapydScript implementation of Python's contextlib standard library.
4
+ #
5
+ # Supported:
6
+ # AbstractContextManager — base class with default __enter__ (returns self)
7
+ # @contextmanager — turn a generator function into a context manager
8
+ # closing(thing) — calls thing.close() on exit
9
+ # nullcontext(val) — no-op context manager; __enter__ returns val
10
+ # suppress(*excs) — silently swallow specified exception types
11
+ # ExitStack — dynamic LIFO stack of context managers / callbacks
12
+ #
13
+ # Usage:
14
+ # from contextlib import contextmanager, suppress, closing, nullcontext, ExitStack
15
+ #
16
+ # @contextmanager
17
+ # def managed(name):
18
+ # print('enter', name)
19
+ # try:
20
+ # yield name.upper()
21
+ # finally:
22
+ # print('exit', name)
23
+ #
24
+ # with managed('hello') as val:
25
+ # print(val) # HELLO
26
+ # # prints: enter hello / HELLO / exit hello
27
+ #
28
+ # with suppress(ValueError):
29
+ # int('not-a-number')
30
+ # # no exception raised
31
+ #
32
+ # stack = ExitStack()
33
+ # with stack:
34
+ # f = stack.enter_context(some_cm())
35
+ #
36
+ # Implementation notes:
37
+ # - contextmanager uses the JS generator protocol (.next() / .throw()).
38
+ # Since 'throw' is a reserved JS keyword it cannot appear as a bare
39
+ # identifier in RapydScript method-call syntax; the call is made via a
40
+ # verbatim v"""...""" block.
41
+ # - The with-statement machinery in RapydScript calls __exit__() (0 args)
42
+ # when no exception occurred and __exit__(exc_type, exc_val, exc_tb)
43
+ # (3 args) when one did. All __exit__ implementations here use default
44
+ # parameters (=None) so both signatures work transparently.
45
+ # - ExitStack.__exit__ may raise a new exception that replaces the original;
46
+ # the with-statement machinery propagates whatever __exit__ throws.
47
+
48
+
49
+ # RuntimeError is not defined in the RapydScript baselib; define it here so
50
+ # that the contextmanager helpers can raise it for protocol violations.
51
+ class RuntimeError(Exception):
52
+ pass
53
+
54
+
55
+ class AbstractContextManager:
56
+ """
57
+ ABC for context managers that provides a default __enter__ returning self.
58
+
59
+ Subclasses must override __exit__. A default no-op __exit__ is also
60
+ provided so that plain subclasses work without override if no cleanup is
61
+ needed.
62
+
63
+ Example::
64
+
65
+ class Timed(AbstractContextManager):
66
+ def __enter__(self):
67
+ self._start = Date.now()
68
+ return self
69
+ def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
70
+ print('elapsed:', Date.now() - self._start, 'ms')
71
+ return False
72
+ """
73
+
74
+ def __enter__(self):
75
+ return self
76
+
77
+ def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
78
+ return None
79
+
80
+
81
+ class closing:
82
+ """
83
+ Context manager that calls thing.close() when the block exits.
84
+
85
+ Equivalent to Python's contextlib.closing.
86
+
87
+ Example::
88
+
89
+ from contextlib import closing
90
+
91
+ with closing(open_connection()) as conn:
92
+ conn.send(data)
93
+ # conn.close() is guaranteed to be called
94
+ """
95
+
96
+ def __init__(self, thing):
97
+ self.thing = thing
98
+
99
+ def __enter__(self):
100
+ return self.thing
101
+
102
+ def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
103
+ self.thing.close()
104
+ return False
105
+
106
+
107
+ class nullcontext:
108
+ """
109
+ No-op context manager. __enter__ returns enter_result (default None).
110
+
111
+ Useful as a conditional stand-in when you optionally want a real context
112
+ manager::
113
+
114
+ cm = open_lock() if need_lock else nullcontext()
115
+ with cm:
116
+ do_work()
117
+
118
+ Also handy for parameterised tests::
119
+
120
+ with nullcontext(42) as val:
121
+ assert val == 42
122
+ """
123
+
124
+ def __init__(self, enter_result=None):
125
+ self.enter_result = enter_result
126
+
127
+ def __enter__(self):
128
+ return self.enter_result
129
+
130
+ def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
131
+ return None
132
+
133
+
134
+ class suppress:
135
+ """
136
+ Context manager that silently suppresses the listed exception types.
137
+
138
+ If a listed exception is raised inside the block the block is exited
139
+ and execution continues after the with statement. Any other exception
140
+ type propagates normally.
141
+
142
+ Example::
143
+
144
+ from contextlib import suppress
145
+
146
+ with suppress(KeyError, ValueError):
147
+ d = {}
148
+ _ = d['missing'] # KeyError suppressed
149
+ # execution continues here
150
+ """
151
+
152
+ def __init__(self, *exceptions):
153
+ self._exceptions = exceptions
154
+
155
+ def __enter__(self):
156
+ return self
157
+
158
+ def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
159
+ if exc_type is None:
160
+ return False
161
+ for exc_class in self._exceptions:
162
+ if isinstance(exc_val, exc_class):
163
+ return True
164
+ return False
165
+
166
+
167
+ def contextmanager(func):
168
+ """
169
+ Decorator that turns a generator function into a context manager.
170
+
171
+ The decorated function must contain exactly one ``yield`` expression.
172
+ Everything before the yield is the __enter__ body; everything after is
173
+ the __exit__ body. The yielded value is bound to the ``as`` target.
174
+
175
+ Exception handling works as in Python: if an exception is raised inside
176
+ the with block it is thrown into the generator at the yield point. The
177
+ generator may catch and suppress it (by not re-raising) or let it
178
+ propagate.
179
+
180
+ Example::
181
+
182
+ from contextlib import contextmanager
183
+
184
+ @contextmanager
185
+ def temp_value(d, key, val):
186
+ old = d.get(key)
187
+ d[key] = val
188
+ try:
189
+ yield val
190
+ finally:
191
+ if old is None:
192
+ del d[key]
193
+ else:
194
+ d[key] = old
195
+
196
+ d = {}
197
+ with temp_value(d, 'x', 99) as v:
198
+ assert v == 99
199
+ assert d['x'] == 99
200
+ assert 'x' not in d
201
+ """
202
+
203
+ def _make_cm(*args, **kwargs):
204
+ gen = func(*args, **kwargs)
205
+
206
+ class _GeneratorContextManager:
207
+
208
+ def __enter__(self):
209
+ r = gen.next()
210
+ if r.done:
211
+ raise RuntimeError('generator did not yield')
212
+ return r.value
213
+
214
+ def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
215
+ if exc_type is None:
216
+ # No-exception path: advance the generator to completion.
217
+ r = gen.next()
218
+ if not r.done:
219
+ raise RuntimeError('generator did not stop after yield')
220
+ return False
221
+ # Exception path: throw exc_val into the generator.
222
+ # 'throw' is a reserved JS keyword so we use verbatim JS.
223
+ v"""
224
+ var ρσ_cm_result;
225
+ try {
226
+ ρσ_cm_result = gen.throw(exc_val);
227
+ } catch (ρσ_cm_err) {
228
+ // Generator did not catch the exception (re-raised or threw a
229
+ // different one). If it's the same object, return false so
230
+ // the with-machinery re-raises it. Otherwise let the new
231
+ // exception propagate from __exit__.
232
+ if (ρσ_cm_err === exc_val) {
233
+ return false;
234
+ }
235
+ throw ρσ_cm_err;
236
+ }
237
+ // Generator caught the exception and returned normally.
238
+ if (!ρσ_cm_result.done) {
239
+ throw new RuntimeError('generator did not stop after throw()');
240
+ }
241
+ return true;
242
+ """
243
+
244
+ return _GeneratorContextManager()
245
+
246
+ return _make_cm
247
+
248
+
249
+ class ExitStack:
250
+ """
251
+ Context manager for dynamic stacks of context managers and callbacks.
252
+
253
+ Maintains a LIFO stack of registered cleanup actions. All registered
254
+ actions are guaranteed to run on exit, even if earlier ones raise.
255
+
256
+ Key methods:
257
+ enter_context(cm) — enter *cm* and push its __exit__ for cleanup
258
+ push(exit_cb) — push a raw (exc_type, exc_val, exc_tb) callback
259
+ or a context manager (its __exit__ is pushed)
260
+ callback(func, *a, **kw) — push func(*a, **kw) as a no-exc callback
261
+ close() — trigger exit immediately (convenience)
262
+
263
+ Example::
264
+
265
+ from contextlib import ExitStack
266
+
267
+ with ExitStack() as stack:
268
+ files = [stack.enter_context(open_file(name)) for name in names]
269
+ # all files closed on exit, even if some raises
270
+
271
+ # Manually-built stack:
272
+ stack = ExitStack()
273
+ conn = stack.enter_context(get_connection())
274
+ stack.callback(log, 'connection cleaned up')
275
+ try:
276
+ use(conn)
277
+ finally:
278
+ stack.close()
279
+ """
280
+
281
+ def __init__(self):
282
+ self._exit_callbacks = []
283
+
284
+ def __enter__(self):
285
+ return self
286
+
287
+ def push(self, exit_or_cm):
288
+ """
289
+ Register an exit callback or a context manager.
290
+
291
+ If *exit_or_cm* has an ``__exit__`` attribute it is treated as a
292
+ context manager (its __exit__ is registered but __enter__ is NOT
293
+ called — use enter_context() if you need that). Otherwise it must be
294
+ a callable with the ``(exc_type, exc_val, exc_tb)`` signature.
295
+
296
+ Returns *exit_or_cm* unchanged, so it can be used as a decorator.
297
+ """
298
+ if hasattr(exit_or_cm, '__exit__'):
299
+ _cm = exit_or_cm
300
+ def _cm_exit(exc_type=None, exc_val=None, exc_tb=None):
301
+ return _cm.__exit__(exc_type, exc_val, exc_tb)
302
+ self._exit_callbacks.append(_cm_exit)
303
+ else:
304
+ self._exit_callbacks.append(exit_or_cm)
305
+ return exit_or_cm
306
+
307
+ def enter_context(self, cm):
308
+ """
309
+ Enter a context manager and push its __exit__ for cleanup.
310
+
311
+ Returns the value returned by cm.__enter__().
312
+ """
313
+ result = cm.__enter__()
314
+ _cm2 = cm
315
+ def _cm2_exit(exc_type=None, exc_val=None, exc_tb=None):
316
+ return _cm2.__exit__(exc_type, exc_val, exc_tb)
317
+ self._exit_callbacks.append(_cm2_exit)
318
+ return result
319
+
320
+ def callback(self, func, *args, **kwargs):
321
+ """
322
+ Register a plain callback to run on exit, ignoring exception info.
323
+
324
+ The callback is called as func(*args, **kwargs) and its return value
325
+ is ignored. Returns *func* unchanged.
326
+ """
327
+ stored_args = args
328
+ stored_kwargs = kwargs
329
+ def _plain_cb(exc_type=None, exc_val=None, exc_tb=None):
330
+ func(*stored_args, **stored_kwargs)
331
+ return False
332
+ self._exit_callbacks.append(_plain_cb)
333
+ return func
334
+
335
+ def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
336
+ """
337
+ Run all registered cleanups in LIFO order.
338
+
339
+ Returns True if an active exception was suppressed by any cleanup.
340
+ If a cleanup raises, that exception becomes the active exception for
341
+ subsequent cleanups; if it is still active at the end it propagates
342
+ from __exit__ (replacing the original).
343
+ """
344
+ received_exc = exc_type is not None
345
+ suppressed = False
346
+
347
+ current_type = exc_type
348
+ current_val = exc_val
349
+ current_tb = exc_tb
350
+
351
+ new_exc = None
352
+ raised_new = False
353
+
354
+ while len(self._exit_callbacks) > 0:
355
+ cb = self._exit_callbacks.pop()
356
+ try:
357
+ result = cb(current_type, current_val, current_tb)
358
+ if result:
359
+ suppressed = True
360
+ current_type = None
361
+ current_val = None
362
+ current_tb = None
363
+ except Exception as e:
364
+ # Cleanup raised — this becomes the active exception.
365
+ new_exc = e
366
+ raised_new = True
367
+ current_type = e.__class__
368
+ current_val = e
369
+ current_tb = None
370
+ suppressed = False
371
+
372
+ if raised_new:
373
+ raise new_exc
374
+
375
+ return received_exc and suppressed
376
+
377
+ def close(self):
378
+ """Exit the stack without an active exception."""
379
+ self.__exit__(None, None, None)