pyscript-programming-language 1.15.0.dev1__py3-none-any.whl → 1.15.2__py3-none-any.whl
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.
- pyscript/__main__.py +11 -9
- pyscript/core/constants.py +2 -1
- pyscript/core/editor/gui.py +16 -8
- pyscript/core/handlers.py +13 -1
- pyscript/core/highlight.py +0 -2
- pyscript/core/interpreter.py +15 -26
- pyscript/core/mapping.py +8 -5
- pyscript/core/nodes.py +56 -19
- pyscript/core/parser.py +92 -61
- pyscript/core/pysbuiltins.py +38 -33
- pyscript/core/pystypes.py +9 -4
- pyscript/core/runner.py +4 -3
- pyscript/core/shell.py +15 -17
- pyscript/core/token.py +1 -0
- pyscript/core/utils/debug.py +2 -2
- pyscript/core/utils/decorators.py +7 -5
- pyscript/core/utils/generic.py +3 -2
- pyscript/core/utils/module.py +3 -0
- pyscript/core/utils/string.py +7 -3
- pyscript/core/version.py +13 -2
- pyscript/lib/brainfuck.pys +17 -23
- pyscript/lib/dual/__init__.pys +5 -3
- pyscript/lib/dual/py_dual.py +103 -64
- pyscript/lib/explorer.pys +53 -75
- pyscript/lib/getch/__init__.pys +2 -1
- pyscript/lib/getch/py_getch.py +7 -4
- pyscript/lib/history.pys +15 -5
- pyscript/lib/site.pys +19 -19
- pyscript/other/message.txt +72 -0
- {pyscript_programming_language-1.15.0.dev1.dist-info → pyscript_programming_language-1.15.2.dist-info}/METADATA +28 -24
- {pyscript_programming_language-1.15.0.dev1.dist-info → pyscript_programming_language-1.15.2.dist-info}/RECORD +34 -33
- {pyscript_programming_language-1.15.0.dev1.dist-info → pyscript_programming_language-1.15.2.dist-info}/WHEEL +1 -1
- /pyscript/{site-packages → lib}/this.pys +0 -0
- {pyscript_programming_language-1.15.0.dev1.dist-info → pyscript_programming_language-1.15.2.dist-info}/top_level.txt +0 -0
pyscript/core/parser.py
CHANGED
|
@@ -401,7 +401,22 @@ class PysParser(Pys):
|
|
|
401
401
|
)
|
|
402
402
|
|
|
403
403
|
def instanceof(self) -> PysParserResult:
|
|
404
|
-
|
|
404
|
+
result = PysParserResult()
|
|
405
|
+
|
|
406
|
+
node = result.try_register(self.binary_operator(
|
|
407
|
+
self.bitwise,
|
|
408
|
+
(TOKENS['KEYWORD'], 'instanceof'),
|
|
409
|
+
(TOKENS['KEYWORD'], 'not'),
|
|
410
|
+
instanceof=True
|
|
411
|
+
))
|
|
412
|
+
|
|
413
|
+
if result.error:
|
|
414
|
+
return result
|
|
415
|
+
elif node:
|
|
416
|
+
return result.success(node)
|
|
417
|
+
|
|
418
|
+
self.reverse(result.to_reverse_count)
|
|
419
|
+
return self.bitwise()
|
|
405
420
|
|
|
406
421
|
def bitwise(self) -> PysParserResult:
|
|
407
422
|
return self.binary_operator(
|
|
@@ -1182,66 +1197,71 @@ class PysParser(Pys):
|
|
|
1182
1197
|
|
|
1183
1198
|
self.skip(result)
|
|
1184
1199
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1200
|
+
cases = []
|
|
1201
|
+
default = None
|
|
1187
1202
|
|
|
1188
|
-
|
|
1203
|
+
if self.current_token.type == TOKENS['SEMICOLON']:
|
|
1204
|
+
result.register_advancement()
|
|
1205
|
+
self.advance()
|
|
1189
1206
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
self.skip(result)
|
|
1207
|
+
elif self.current_token.type == TOKENS['LEFT_CURLY']:
|
|
1208
|
+
left_bracket_token = self.current_token
|
|
1193
1209
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1210
|
+
result.register_advancement()
|
|
1211
|
+
self.advance()
|
|
1212
|
+
self.skip(result)
|
|
1196
1213
|
|
|
1197
|
-
|
|
1214
|
+
while True:
|
|
1198
1215
|
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1216
|
+
if self.current_token.match(TOKENS['KEYWORD'], 'case'):
|
|
1217
|
+
result.register_advancement()
|
|
1218
|
+
self.advance()
|
|
1219
|
+
self.skip(result)
|
|
1203
1220
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1221
|
+
case = result.register(self.walrus(), True)
|
|
1222
|
+
if result.error:
|
|
1223
|
+
return result
|
|
1207
1224
|
|
|
1208
|
-
|
|
1225
|
+
self.skip(result)
|
|
1209
1226
|
|
|
1210
|
-
|
|
1211
|
-
|
|
1227
|
+
if self.current_token.type != TOKENS['COLON']:
|
|
1228
|
+
return result.failure(self.new_error("expected ':'"))
|
|
1212
1229
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1230
|
+
result.register_advancement()
|
|
1231
|
+
self.advance()
|
|
1215
1232
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1233
|
+
body = result.register(self.statements())
|
|
1234
|
+
if result.error:
|
|
1235
|
+
return result
|
|
1219
1236
|
|
|
1220
|
-
|
|
1237
|
+
cases.append((case, body))
|
|
1221
1238
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1239
|
+
elif self.current_token.match(TOKENS['KEYWORD'], 'default', 'else'):
|
|
1240
|
+
result.register_advancement()
|
|
1241
|
+
self.advance()
|
|
1242
|
+
self.skip(result)
|
|
1226
1243
|
|
|
1227
|
-
|
|
1228
|
-
|
|
1244
|
+
if self.current_token.type != TOKENS['COLON']:
|
|
1245
|
+
return result.failure(self.new_error("expected ':'"))
|
|
1229
1246
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1247
|
+
result.register_advancement()
|
|
1248
|
+
self.advance()
|
|
1232
1249
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1250
|
+
default = result.register(self.statements())
|
|
1251
|
+
if result.error:
|
|
1252
|
+
return result
|
|
1236
1253
|
|
|
1237
|
-
|
|
1254
|
+
break
|
|
1238
1255
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1256
|
+
else:
|
|
1257
|
+
break
|
|
1241
1258
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1259
|
+
self.close_bracket(result, left_bracket_token)
|
|
1260
|
+
if result.error:
|
|
1261
|
+
return result
|
|
1262
|
+
|
|
1263
|
+
else:
|
|
1264
|
+
return result.failure(self.new_error("expected '{'"))
|
|
1245
1265
|
|
|
1246
1266
|
return result.success(
|
|
1247
1267
|
PysSwitchNode(
|
|
@@ -2325,15 +2345,12 @@ class PysParser(Pys):
|
|
|
2325
2345
|
if result.error:
|
|
2326
2346
|
return result
|
|
2327
2347
|
|
|
2328
|
-
if body.__class__
|
|
2329
|
-
setimuattr(
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
end
|
|
2335
|
-
)
|
|
2336
|
-
)
|
|
2348
|
+
if body.__class__ is PysStatementsNode:
|
|
2349
|
+
setimuattr(body, 'position', PysPosition(
|
|
2350
|
+
self.current_token.position.file,
|
|
2351
|
+
left_bracket_token.position.start,
|
|
2352
|
+
end
|
|
2353
|
+
))
|
|
2337
2354
|
|
|
2338
2355
|
return result.success(body)
|
|
2339
2356
|
|
|
@@ -2350,10 +2367,7 @@ class PysParser(Pys):
|
|
|
2350
2367
|
|
|
2351
2368
|
body = result.register(self.statement())
|
|
2352
2369
|
if result.error:
|
|
2353
|
-
return result.failure(
|
|
2354
|
-
self.new_error("expected statement, expression, '{', or ';'"),
|
|
2355
|
-
fatal=False
|
|
2356
|
-
)
|
|
2370
|
+
return result.failure(self.new_error("expected statement, expression, '{', or ';'"), fatal=False)
|
|
2357
2371
|
|
|
2358
2372
|
return result.success(body)
|
|
2359
2373
|
|
|
@@ -2393,7 +2407,7 @@ class PysParser(Pys):
|
|
|
2393
2407
|
self.skip_expression(result)
|
|
2394
2408
|
|
|
2395
2409
|
if not self.current_token.match(TOKENS['KEYWORD'], 'in'):
|
|
2396
|
-
return result.failure(self.new_error("expected 'in'"))
|
|
2410
|
+
return result.failure(self.new_error("expected 'in' or 'instanceof'"))
|
|
2397
2411
|
|
|
2398
2412
|
operations[-1] = PysToken(
|
|
2399
2413
|
TOKENS['EXCLAMATION_GREATER_THAN'],
|
|
@@ -2483,11 +2497,28 @@ class PysParser(Pys):
|
|
|
2483
2497
|
TOKENS['DOUBLE_AMPERSAND' if token.value == 'and' else 'DOUBLE_PIPE'],
|
|
2484
2498
|
token.position
|
|
2485
2499
|
)
|
|
2500
|
+
|
|
2486
2501
|
elif instanceof:
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2502
|
+
|
|
2503
|
+
if token.match(TOKENS['KEYWORD'], 'not'):
|
|
2504
|
+
result.register_advancement()
|
|
2505
|
+
self.advance()
|
|
2506
|
+
self.skip_expression(result)
|
|
2507
|
+
|
|
2508
|
+
if not self.current_token.match(TOKENS['KEYWORD'], 'instanceof'):
|
|
2509
|
+
return result.failure(self.new_error("expected 'instanceof'"), fatal=False)
|
|
2510
|
+
|
|
2511
|
+
operand = PysToken(
|
|
2512
|
+
TOKENS['NOT_INSTANCEOF'],
|
|
2513
|
+
token.position
|
|
2514
|
+
)
|
|
2515
|
+
|
|
2516
|
+
else:
|
|
2517
|
+
operand = PysToken(
|
|
2518
|
+
TOKENS['INSTANCEOF'],
|
|
2519
|
+
token.position
|
|
2520
|
+
)
|
|
2521
|
+
|
|
2491
2522
|
else:
|
|
2492
2523
|
operand = token
|
|
2493
2524
|
|
pyscript/core/pysbuiltins.py
CHANGED
|
@@ -37,6 +37,7 @@ static_wrapper_function = (staticmethod,)
|
|
|
37
37
|
wrapper_function = (MethodType, PysPythonFunction, classmethod)
|
|
38
38
|
python_function = (BuiltinFunctionType, BuiltinMethodType, FunctionType)
|
|
39
39
|
|
|
40
|
+
pynewobject = object.__new__
|
|
40
41
|
pyvars = builtins.vars
|
|
41
42
|
pydir = builtins.dir
|
|
42
43
|
|
|
@@ -55,34 +56,36 @@ def _magic_method(
|
|
|
55
56
|
return NotImplemented
|
|
56
57
|
|
|
57
58
|
def _unpack_comprehension_function(context: PysContext, position: PysPosition, function: Callable) -> Callable:
|
|
58
|
-
check = function
|
|
59
|
-
|
|
60
|
-
offset = 0
|
|
59
|
+
check = final = function
|
|
60
|
+
length = offset = 0
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
b_isinstance = isinstance
|
|
63
|
+
|
|
64
|
+
if b_isinstance(function, wrapper_function):
|
|
63
65
|
check = function.__func__
|
|
64
|
-
offset += 2 if
|
|
65
|
-
elif
|
|
66
|
+
offset += 2 if b_isinstance(function, PysPythonFunction) else 1
|
|
67
|
+
elif b_isinstance(function, static_wrapper_function):
|
|
66
68
|
check = function.__func__
|
|
69
|
+
elif b_isinstance(function, type):
|
|
70
|
+
offset += 1
|
|
71
|
+
check = function.__new__
|
|
72
|
+
if check is pynewobject:
|
|
73
|
+
check = function.__init__
|
|
67
74
|
|
|
68
|
-
if
|
|
75
|
+
if b_isinstance(check, PysFunction):
|
|
69
76
|
length = max(check.__code__.parameters_length - offset, 0)
|
|
70
|
-
|
|
71
|
-
def final(item):
|
|
72
|
-
return function()
|
|
73
|
-
elif length > 1:
|
|
74
|
-
def final(item):
|
|
75
|
-
return function(*item)
|
|
76
|
-
|
|
77
|
-
elif isinstance(check, python_function):
|
|
77
|
+
elif b_isinstance(check, python_function):
|
|
78
78
|
parameters = signature(check).parameters
|
|
79
79
|
length = max(len(parameters) - offset, 0)
|
|
80
|
-
if length ==
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
if length == 1 and any(p.kind == p.VAR_POSITIONAL for p in parameters.values()):
|
|
81
|
+
length = 2
|
|
82
|
+
|
|
83
|
+
if length == 0:
|
|
84
|
+
def final(item):
|
|
85
|
+
return function()
|
|
86
|
+
elif length > 1:
|
|
87
|
+
def final(item):
|
|
88
|
+
return function(*item)
|
|
86
89
|
|
|
87
90
|
handle_call(function, context, position)
|
|
88
91
|
return final
|
|
@@ -116,8 +119,7 @@ def require(context, position, name):
|
|
|
116
119
|
name: A name or path of the module to be imported.
|
|
117
120
|
"""
|
|
118
121
|
|
|
119
|
-
name, *
|
|
120
|
-
|
|
122
|
+
name, *components = normstr(name).split('>')
|
|
121
123
|
filename = context.file.name
|
|
122
124
|
path, module_path = find_module_path(filename, name)
|
|
123
125
|
|
|
@@ -189,9 +191,8 @@ def require(context, position, name):
|
|
|
189
191
|
finally:
|
|
190
192
|
loading_modules.discard(module_path)
|
|
191
193
|
|
|
192
|
-
for component in
|
|
194
|
+
for component in components:
|
|
193
195
|
module = getattr(module, component)
|
|
194
|
-
|
|
195
196
|
return module
|
|
196
197
|
|
|
197
198
|
@PysBuiltinFunction
|
|
@@ -386,7 +387,7 @@ def dir(context, position, *args):
|
|
|
386
387
|
def exec(context, position, source, globals=None):
|
|
387
388
|
|
|
388
389
|
"""
|
|
389
|
-
exec(source: str | bytes, globals: Optional[dict]) -> None
|
|
390
|
+
exec(source: str | bytes | bytearray | Iterable | IOBase, globals: Optional[dict] = None) -> None
|
|
390
391
|
|
|
391
392
|
Executes PyScript code statements from the given source.
|
|
392
393
|
|
|
@@ -416,7 +417,7 @@ def exec(context, position, source, globals=None):
|
|
|
416
417
|
def eval(context, position, source, globals=None):
|
|
417
418
|
|
|
418
419
|
"""
|
|
419
|
-
eval(source: str | bytes, globals: Optional[dict]) -> None
|
|
420
|
+
eval(source: str | bytes | bytearray | Iterable | IOBase, globals: Optional[dict] = None) -> None
|
|
420
421
|
|
|
421
422
|
Executes a PyScript code expression from the given source.
|
|
422
423
|
|
|
@@ -460,7 +461,8 @@ def ce(context, position, a, b, *, rel_tol=1e-9, abs_tol=0):
|
|
|
460
461
|
abs_tol: maximum difference for being considered "close", regardless of the magnitude of the input values.
|
|
461
462
|
"""
|
|
462
463
|
|
|
463
|
-
|
|
464
|
+
b_isinstance = isinstance
|
|
465
|
+
if b_isinstance(a, real_complex_number) and b_isinstance(b, real_complex_number):
|
|
464
466
|
return isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol)
|
|
465
467
|
|
|
466
468
|
result = _magic_method(context, position, a, '__ce__', b, rel_tol=rel_tol, abs_tol=abs_tol)
|
|
@@ -494,7 +496,8 @@ def nce(context, position, a, b, *, rel_tol=1e-9, abs_tol=0):
|
|
|
494
496
|
abs_tol: maximum difference for being considered "close", regardless of the magnitude of the input values.
|
|
495
497
|
"""
|
|
496
498
|
|
|
497
|
-
|
|
499
|
+
b_isinstance = isinstance
|
|
500
|
+
if b_isinstance(a, real_complex_number) and b_isinstance(b, real_complex_number):
|
|
498
501
|
return not isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol)
|
|
499
502
|
|
|
500
503
|
result = _magic_method(context, position, a, '__nce__', b, rel_tol=rel_tol, abs_tol=abs_tol)
|
|
@@ -525,9 +528,10 @@ def increment(context, position, object):
|
|
|
525
528
|
__increment__ method, which if unsuccessful will throw a TypeError.
|
|
526
529
|
"""
|
|
527
530
|
|
|
528
|
-
|
|
531
|
+
b_isinstance = isinstance
|
|
532
|
+
if b_isinstance(object, real_number):
|
|
529
533
|
return object + 1
|
|
530
|
-
elif
|
|
534
|
+
elif b_isinstance(object, sequence):
|
|
531
535
|
return tuple(_pyincrement(context, position, obj) for obj in object)
|
|
532
536
|
|
|
533
537
|
result = _magic_method(context, position, object, '__increment__')
|
|
@@ -549,9 +553,10 @@ def decrement(context, position, object):
|
|
|
549
553
|
call the __decrement__ method, which if unsuccessful will throw a TypeError.
|
|
550
554
|
"""
|
|
551
555
|
|
|
552
|
-
|
|
556
|
+
b_isinstance = isinstance
|
|
557
|
+
if b_isinstance(object, real_number):
|
|
553
558
|
return object - 1
|
|
554
|
-
elif
|
|
559
|
+
elif b_isinstance(object, sequence):
|
|
555
560
|
return tuple(_pydecrement(context, position, obj) for obj in object)
|
|
556
561
|
|
|
557
562
|
result = _magic_method(context, position, object, '__decrement__')
|
pyscript/core/pystypes.py
CHANGED
|
@@ -11,7 +11,6 @@ from .utils.generic import setimuattr, dinit, drepr, dor, dror, dior, dsetitem,
|
|
|
11
11
|
from .utils.similarity import diff_get_closest
|
|
12
12
|
from .utils.string import join
|
|
13
13
|
|
|
14
|
-
from builtins import help as pyhelp
|
|
15
14
|
from itertools import islice
|
|
16
15
|
from types import MethodType
|
|
17
16
|
from typing import Any, Callable, Optional
|
|
@@ -203,7 +202,7 @@ class PysFunction(PysObject):
|
|
|
203
202
|
PysTraceback(
|
|
204
203
|
TypeError(
|
|
205
204
|
f"{self.__qualname__}() missing {total_missing} required positional argument"
|
|
206
|
-
f"{'' if total_missing == 1 else 's'}: {join(missing_arguments
|
|
205
|
+
f"{'' if total_missing == 1 else 's'}: {join(missing_arguments)}"
|
|
207
206
|
),
|
|
208
207
|
context,
|
|
209
208
|
position
|
|
@@ -311,10 +310,16 @@ class PysPrinter(PysObject):
|
|
|
311
310
|
|
|
312
311
|
class PysHelper(PysPrinter):
|
|
313
312
|
|
|
314
|
-
__slots__ = ()
|
|
313
|
+
__slots__ = ('_pyhelp',)
|
|
315
314
|
|
|
316
315
|
def __init__(self) -> None:
|
|
317
316
|
super().__init__('help')
|
|
317
|
+
try:
|
|
318
|
+
from builtins import help
|
|
319
|
+
except:
|
|
320
|
+
def help(*args, **kwargs):
|
|
321
|
+
raise NotImplementedError('python builtins.help not found')
|
|
322
|
+
setimuattr(self, '_pyhelp', help)
|
|
318
323
|
|
|
319
324
|
def __repr__(self) -> str:
|
|
320
325
|
return f'Type {self.name}() for interactive help, or {self.name}(object) for help about object.'
|
|
@@ -328,4 +333,4 @@ class PysHelper(PysPrinter):
|
|
|
328
333
|
"To get the list of builtin functions, types, exceptions, and other objects, type 'help(\"builtins\")'."
|
|
329
334
|
)
|
|
330
335
|
else:
|
|
331
|
-
|
|
336
|
+
self._pyhelp(*args, **kwargs)
|
pyscript/core/runner.py
CHANGED
|
@@ -153,13 +153,14 @@ def pys_runner(
|
|
|
153
153
|
pys_sys.flags = context.flags
|
|
154
154
|
|
|
155
155
|
try:
|
|
156
|
-
del
|
|
157
|
-
lexer, tokens, error, parser,
|
|
156
|
+
del (
|
|
157
|
+
file, flags, symbol_table, context_parent, context_parent_entry_position, lexer, tokens, error, parser,
|
|
158
|
+
analyzer
|
|
159
|
+
)
|
|
158
160
|
except:
|
|
159
161
|
pass
|
|
160
162
|
|
|
161
163
|
visitor_result = get_visitor(node.__class__)(node, context)
|
|
162
|
-
|
|
163
164
|
if visitor_result.error:
|
|
164
165
|
return result.failure(visitor_result.error)
|
|
165
166
|
|
pyscript/core/shell.py
CHANGED
|
@@ -233,10 +233,8 @@ try:
|
|
|
233
233
|
@singleton
|
|
234
234
|
class PysHistory(Pys, History):
|
|
235
235
|
|
|
236
|
-
def __new_singleton__(cls) -> 'PysHistory':
|
|
237
|
-
if USE_FILE_HISTORY
|
|
238
|
-
return super().__new__(cls)
|
|
239
|
-
raise NotImplementedError('not using file history')
|
|
236
|
+
def __new_singleton__(cls) -> 'PysHistory | InMemoryHistory':
|
|
237
|
+
return super().__new__(cls) if USE_FILE_HISTORY else InMemoryHistory()
|
|
240
238
|
|
|
241
239
|
def _write_history_safely(self, mode: str, function: str, *args) -> None:
|
|
242
240
|
try:
|
|
@@ -254,16 +252,16 @@ try:
|
|
|
254
252
|
self._write_history_safely('w', 'write', '')
|
|
255
253
|
return []
|
|
256
254
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
lines = []
|
|
255
|
+
strings = []
|
|
256
|
+
lines = []
|
|
260
257
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
258
|
+
def add_to_string():
|
|
259
|
+
if not lines:
|
|
260
|
+
return
|
|
261
|
+
strings.insert(0, '\n'.join(lines))
|
|
262
|
+
lines.clear()
|
|
266
263
|
|
|
264
|
+
try:
|
|
267
265
|
with open(HISTORY_PATH, 'r', encoding=pys_sys.encoding) as file:
|
|
268
266
|
for line in file:
|
|
269
267
|
line = line[:-1]
|
|
@@ -273,13 +271,15 @@ try:
|
|
|
273
271
|
lines.append(line)
|
|
274
272
|
add_to_string()
|
|
275
273
|
|
|
276
|
-
if
|
|
274
|
+
if 0 < HISTORY_LIMIT < len(strings):
|
|
277
275
|
self._manage_history_capacity(strings)
|
|
278
276
|
|
|
279
|
-
return strings
|
|
280
277
|
except:
|
|
281
278
|
return []
|
|
282
279
|
|
|
280
|
+
else:
|
|
281
|
+
return strings
|
|
282
|
+
|
|
283
283
|
# this function is called within `append_string()` which adds a new string or history entry to `_loaded_strings`
|
|
284
284
|
# before invoking this function
|
|
285
285
|
def store_string(self, string: str) -> None:
|
|
@@ -290,8 +290,6 @@ try:
|
|
|
290
290
|
else:
|
|
291
291
|
self._manage_history_capacity(self._loaded_strings)
|
|
292
292
|
|
|
293
|
-
history = (PysHistory if USE_FILE_HISTORY else InMemoryHistory)()
|
|
294
|
-
|
|
295
293
|
class PysPromptToolkitLineShell(PysLineShell, PromptSession):
|
|
296
294
|
|
|
297
295
|
def __init__(self, ps1: str = '>>> ', ps2: str = '... ', colored: bool = True) -> None:
|
|
@@ -381,7 +379,7 @@ try:
|
|
|
381
379
|
input_processors=[TabsProcessor(tabstop=4)],
|
|
382
380
|
key_bindings=key_bindings,
|
|
383
381
|
prompt_continuation=lambda width, line_number, is_soft_wrap: self._ps2,
|
|
384
|
-
history=
|
|
382
|
+
history=PysHistory(),
|
|
385
383
|
**other_keyword
|
|
386
384
|
)
|
|
387
385
|
|
pyscript/core/token.py
CHANGED
pyscript/core/utils/debug.py
CHANGED
|
@@ -40,13 +40,13 @@ def import_readline() -> Literal[False]:
|
|
|
40
40
|
USE_NOTEBOOK = False
|
|
41
41
|
|
|
42
42
|
try:
|
|
43
|
-
from IPython import get_ipython
|
|
43
|
+
from IPython import get_ipython # type: ignore
|
|
44
44
|
if type(get_ipython()).__name__ in (
|
|
45
45
|
'ZMQInteractiveShell', # Jupyter Notebook / Lab
|
|
46
46
|
'Shell', # Google Colab
|
|
47
47
|
'TerminalInteractiveShell' # IPython Terminal
|
|
48
48
|
):
|
|
49
|
-
from IPython.display import clear_output
|
|
49
|
+
from IPython.display import clear_output # type: ignore
|
|
50
50
|
def clear_shell() -> None:
|
|
51
51
|
clear_output()
|
|
52
52
|
USE_NOTEBOOK = True
|
|
@@ -13,9 +13,10 @@ class _PysUtilities(Pys):
|
|
|
13
13
|
# circular import problem solved
|
|
14
14
|
from ..cache import pys_sys
|
|
15
15
|
singletons = pys_sys.singletons
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
object = singletons.get(cls, None)
|
|
17
|
+
if type(object) is not cls:
|
|
18
|
+
singletons[cls] = object = cls.__new_singleton__(cls, *args, **kwargs)
|
|
19
|
+
return object
|
|
19
20
|
|
|
20
21
|
@staticmethod
|
|
21
22
|
def readonly_attribute(*args, **kwargs):
|
|
@@ -34,10 +35,11 @@ def typecheck(func, *args, **kwargs):
|
|
|
34
35
|
if not is_environ(ENV_PYSCRIPT_NO_TYPECHECK):
|
|
35
36
|
try:
|
|
36
37
|
from beartype import beartype as typecheck
|
|
37
|
-
TYPECHECK_STACK += 1
|
|
38
|
-
BEARTYPE = True
|
|
39
38
|
except:
|
|
40
39
|
pass
|
|
40
|
+
else:
|
|
41
|
+
TYPECHECK_STACK += 1
|
|
42
|
+
BEARTYPE = True
|
|
41
43
|
|
|
42
44
|
def immutable(cls):
|
|
43
45
|
cls.__setattr__ = _PysUtilities.readonly_attribute
|
pyscript/core/utils/generic.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from inspect import currentframe
|
|
2
|
-
from types import FrameType,
|
|
2
|
+
from types import FrameType, UnionType
|
|
3
3
|
from typing import Any, Optional, Sequence
|
|
4
4
|
|
|
5
5
|
import os
|
|
@@ -21,10 +21,11 @@ dclear = dict.clear
|
|
|
21
21
|
dget = dict.get
|
|
22
22
|
dkeys = dict.keys
|
|
23
23
|
ditems = dict.items
|
|
24
|
-
dfrozen = MappingProxyType
|
|
25
24
|
|
|
26
25
|
if sys.version_info >= (3, 15):
|
|
27
26
|
dfrozen = frozendict
|
|
27
|
+
else:
|
|
28
|
+
from types import MappingProxyType as dfrozen
|
|
28
29
|
|
|
29
30
|
def get_frame(deep: int = 0) -> FrameType | None:
|
|
30
31
|
deep += 1
|
pyscript/core/utils/module.py
CHANGED
|
@@ -22,6 +22,9 @@ def get_module_candidate(path: str, entry: str = '__init__') -> str | None:
|
|
|
22
22
|
return candidate
|
|
23
23
|
|
|
24
24
|
def find_module_path(filename: str | None, name: str, entry: str = '__init__') -> tuple[str | None, str | None]:
|
|
25
|
+
if name in ('_pyscript', 'builtins', 'sys'):
|
|
26
|
+
return None, None
|
|
27
|
+
|
|
25
28
|
# circular import problem solved
|
|
26
29
|
from ..cache import pys_sys
|
|
27
30
|
|
pyscript/core/utils/string.py
CHANGED
|
@@ -38,11 +38,15 @@ def normstr(obj) -> str:
|
|
|
38
38
|
|
|
39
39
|
def join(sequence: Sequence[str], conjunction: str = 'and') -> str:
|
|
40
40
|
length = len(sequence)
|
|
41
|
-
if length ==
|
|
41
|
+
if length == 0:
|
|
42
|
+
return ''
|
|
43
|
+
elif length == 1:
|
|
42
44
|
return sequence[0]
|
|
43
45
|
elif length == 2:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
a, b = sequence
|
|
47
|
+
return f'{a} {conjunction} {b}'
|
|
48
|
+
*others, end = sequence
|
|
49
|
+
return f'{", ".join(others)}, {conjunction} {end}'
|
|
46
50
|
|
|
47
51
|
def indent(string: str, length: int, indent: str = ' ') -> str:
|
|
48
52
|
prefix = indent * length
|
pyscript/core/version.py
CHANGED
|
@@ -4,9 +4,11 @@ from .mapping import TAG_VERSION_MAP
|
|
|
4
4
|
from .utils.decorators import immutable, inheritable, singleton
|
|
5
5
|
|
|
6
6
|
from re import match as match_regex
|
|
7
|
+
from types import NotImplementedType
|
|
8
|
+
from typing import Any
|
|
7
9
|
|
|
8
|
-
__version__ = '1.15.
|
|
9
|
-
__date__ = '
|
|
10
|
+
__version__ = '1.15.2'
|
|
11
|
+
__date__ = '08 November 2026, 12:30 UTC+7'
|
|
10
12
|
__author__ = ('AzzamMuhyala',)
|
|
11
13
|
|
|
12
14
|
version = pys_sys.version = f'{__version__} ({__date__})'
|
|
@@ -72,6 +74,15 @@ class PysVersionInfo(Pys, tuple):
|
|
|
72
74
|
def release(self) -> tuple[int, int, int]:
|
|
73
75
|
return self[0:3]
|
|
74
76
|
|
|
77
|
+
def __add__(self, other: Any) -> NotImplementedType:
|
|
78
|
+
return NotImplemented
|
|
79
|
+
|
|
80
|
+
def __mul__(self, other: Any) -> NotImplementedType:
|
|
81
|
+
return NotImplemented
|
|
82
|
+
|
|
83
|
+
def __rmul__(self, other: Any) -> NotImplementedType:
|
|
84
|
+
return NotImplemented
|
|
85
|
+
|
|
75
86
|
def __lt__(self, other: tuple) -> bool:
|
|
76
87
|
return self.release < other
|
|
77
88
|
|