pyscript-programming-language 1.15.1__tar.gz → 1.15.3__tar.gz

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.
Files changed (92) hide show
  1. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/PKG-INFO +9 -15
  2. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/README.md +8 -14
  3. pyscript_programming_language-1.15.3/changelog.md +13 -0
  4. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyproject.toml +1 -1
  5. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/__main__.py +2 -2
  6. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/cache.py +4 -1
  7. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/constants.py +3 -1
  8. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/editor/gui.py +18 -1
  9. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/editor/terminal.py +16 -0
  10. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/handlers.py +11 -1
  11. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/highlight.py +0 -1
  12. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/interpreter.py +9 -5
  13. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/nodes.py +44 -16
  14. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/parser.py +47 -42
  15. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/pysbuiltins.py +10 -6
  16. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/pystypes.py +8 -3
  17. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/runner.py +1 -1
  18. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/shell.py +30 -20
  19. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/decorators.py +4 -3
  20. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/string.py +4 -2
  21. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/version.py +2 -2
  22. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/dual/py_dual.py +11 -17
  23. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/explorer.pys +53 -75
  24. pyscript_programming_language-1.15.3/pyscript/lib/getch/__init__.pys +11 -0
  25. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/getch/py_getch.py +5 -2
  26. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/history.pys +15 -5
  27. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/site.pys +43 -22
  28. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/other/message.txt +54 -1
  29. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript_programming_language.egg-info/PKG-INFO +9 -15
  30. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript_programming_language.egg-info/SOURCES.txt +1 -1
  31. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/setup.py +1 -1
  32. pyscript_programming_language-1.15.1/changelog.md +0 -13
  33. pyscript_programming_language-1.15.1/pyscript/lib/getch/__init__.pys +0 -10
  34. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/MANIFEST.in +0 -0
  35. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/__init__.py +0 -0
  36. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/__init__.pyi +0 -0
  37. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/__init__.py +0 -0
  38. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/analyzer.py +0 -0
  39. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/bases.py +0 -0
  40. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/buffer.py +0 -0
  41. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/checks.py +0 -0
  42. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/context.py +0 -0
  43. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/editor/__init__.py +0 -0
  44. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/editor/bases.py +0 -0
  45. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/exceptions.py +0 -0
  46. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/lexer.py +0 -0
  47. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/mapping.py +0 -0
  48. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/position.py +0 -0
  49. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/results.py +0 -0
  50. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/symtab.py +0 -0
  51. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/token.py +0 -0
  52. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/__init__.py +0 -0
  53. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/ansi.py +0 -0
  54. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/debug.py +0 -0
  55. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/generic.py +0 -0
  56. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/module.py +0 -0
  57. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/path.py +0 -0
  58. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/core/utils/similarity.py +0 -0
  59. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/__hello__.pys +0 -0
  60. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/ansi.pys +0 -0
  61. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/ast/__init__.pys +0 -0
  62. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/ast/ast_dump.py +0 -0
  63. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/ast/ast_literal_eval.py +0 -0
  64. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/ast/ast_unparse.py +0 -0
  65. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/ast/ast_walk.py +0 -0
  66. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/brainfuck.pys +0 -0
  67. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/code.pys +0 -0
  68. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/dis.pys +0 -0
  69. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/dual/__init__.pys +0 -0
  70. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/fpstimer/__init__.pys +0 -0
  71. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/fpstimer/py_fpstimer.py +0 -0
  72. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/inspect.pys +0 -0
  73. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/jsdict.pys +0 -0
  74. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/keyword.pys +0 -0
  75. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/opcode.pys +0 -0
  76. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/parser.pys +0 -0
  77. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/pdisplay.pys +0 -0
  78. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/symtable.pys +0 -0
  79. {pyscript_programming_language-1.15.1/pyscript/site-packages → pyscript_programming_language-1.15.3/pyscript/lib}/this.pys +0 -0
  80. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/token.pys +0 -0
  81. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/tokenize/__init__.pys +0 -0
  82. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/lib/tokenize/tok_untokenize.py +0 -0
  83. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/other/.nomedia +0 -0
  84. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/other/PyScript.ico +0 -0
  85. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/other/copyright +0 -0
  86. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/other/credits +0 -0
  87. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/other/license +0 -0
  88. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript/this.py +0 -0
  89. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript_programming_language.egg-info/dependency_links.txt +0 -0
  90. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript_programming_language.egg-info/requires.txt +0 -0
  91. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/pyscript_programming_language.egg-info/top_level.txt +0 -0
  92. {pyscript_programming_language-1.15.1 → pyscript_programming_language-1.15.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyscript-programming-language
3
- Version: 1.15.1
3
+ Version: 1.15.3
4
4
  Summary: PyScript Programming Language
5
5
  Home-page: https://azzammuhyala.github.io/pyscript
6
6
  Author: AzzamMuhyala
@@ -69,8 +69,8 @@ Try [PyScript Shell (_REPL_)](https://azzammuhyala.github.io/pyscript/shell.html
69
69
  (no installation required).
70
70
 
71
71
  ## Installation ⬇️
72
- First, you'll need to download Python. Make sure you're using the latest version above `3.10`, to ensure the code runs
73
- correctly. Visit the official [Python website](https://python.org) to download it.
72
+ First, you'll need to download Python. Make sure you're using the latest version **above `3.10`**, to ensure the code
73
+ runs correctly. Visit the official [Python website](https://python.org) to download it.
74
74
 
75
75
  Next, after downloading and configuring the Python application, you can download the PyScript from
76
76
  [PyScript releases](https://github.com/azzammuhyala/pyscript/releases) or from PIP with this command (_Recommended_):
@@ -83,13 +83,6 @@ pip install -U pyscript-programming-language
83
83
  pip install -U pyscript-programming-language[other]
84
84
  ```
85
85
 
86
- And also, you can download PyScript with `git`:
87
- ```sh
88
- git clone https://github.com/azzammuhyala/pyscript
89
- cd pyscript
90
- pip install .
91
- ```
92
-
93
86
  After that, you can run the PyScript shell (_REPL_) with this command:
94
87
  ```sh
95
88
  python -m pyscript
@@ -119,11 +112,12 @@ Familiar? There it is!
119
112
  | 14 | `os` | **required** |
120
113
  | 15 | `pkgutil` | **required** |
121
114
  | 16 | `re` | **required** |
122
- | 17 | `subprocess` | **required** |
123
- | 18 | `sys` | **required** |
124
- | 19 | `types` | **required** |
125
- | 20 | `typing` | **required** |
126
- | 21 | `unicodedata` | **required** |
115
+ | 17 | `site` | **required** |
116
+ | 18 | `subprocess` | **required** |
117
+ | 19 | `sys` | **required** |
118
+ | 20 | `types` | **required** |
119
+ | 21 | `typing` | **required** |
120
+ | 22 | `unicodedata` | **required** |
127
121
  | 1 | `ast` | **required (library)** |
128
122
  | 2 | `math` | **required (library)** |
129
123
  | 3 | `msvcrt` | **required (library)** |
@@ -37,8 +37,8 @@ Try [PyScript Shell (_REPL_)](https://azzammuhyala.github.io/pyscript/shell.html
37
37
  (no installation required).
38
38
 
39
39
  ## Installation ⬇️
40
- First, you'll need to download Python. Make sure you're using the latest version above `3.10`, to ensure the code runs
41
- correctly. Visit the official [Python website](https://python.org) to download it.
40
+ First, you'll need to download Python. Make sure you're using the latest version **above `3.10`**, to ensure the code
41
+ runs correctly. Visit the official [Python website](https://python.org) to download it.
42
42
 
43
43
  Next, after downloading and configuring the Python application, you can download the PyScript from
44
44
  [PyScript releases](https://github.com/azzammuhyala/pyscript/releases) or from PIP with this command (_Recommended_):
@@ -51,13 +51,6 @@ pip install -U pyscript-programming-language
51
51
  pip install -U pyscript-programming-language[other]
52
52
  ```
53
53
 
54
- And also, you can download PyScript with `git`:
55
- ```sh
56
- git clone https://github.com/azzammuhyala/pyscript
57
- cd pyscript
58
- pip install .
59
- ```
60
-
61
54
  After that, you can run the PyScript shell (_REPL_) with this command:
62
55
  ```sh
63
56
  python -m pyscript
@@ -87,11 +80,12 @@ Familiar? There it is!
87
80
  | 14 | `os` | **required** |
88
81
  | 15 | `pkgutil` | **required** |
89
82
  | 16 | `re` | **required** |
90
- | 17 | `subprocess` | **required** |
91
- | 18 | `sys` | **required** |
92
- | 19 | `types` | **required** |
93
- | 20 | `typing` | **required** |
94
- | 21 | `unicodedata` | **required** |
83
+ | 17 | `site` | **required** |
84
+ | 18 | `subprocess` | **required** |
85
+ | 19 | `sys` | **required** |
86
+ | 20 | `types` | **required** |
87
+ | 21 | `typing` | **required** |
88
+ | 22 | `unicodedata` | **required** |
95
89
  | 1 | `ast` | **required (library)** |
96
90
  | 2 | `math` | **required (library)** |
97
91
  | 3 | `msvcrt` | **required (library)** |
@@ -0,0 +1,13 @@
1
+ # Change Logs
2
+
3
+ ## [1.15.3] - 10/11/2026
4
+
5
+ ### Added
6
+ - Some functions in the `site` library now raise exceptions if `ENABLE_USER_SITE` is `None`.
7
+ - _etc._
8
+
9
+ ### Fixed
10
+ - The user site-packages path has been moved to `site.getusersitepackages()` + `/pyscript/site-packages`.
11
+ - The **Shift** + **Tab** shortcut now performs a dedent to the one tab character.
12
+ - Fixed several bugs.
13
+ - _etc._
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyscript-programming-language"
7
- version = "1.15.1"
7
+ version = "1.15.3"
8
8
  description = "PyScript Programming Language"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.10"
@@ -139,7 +139,7 @@ parser.add_argument(
139
139
  parser.add_argument(
140
140
  '-t', '--terminal',
141
141
  action='store_true',
142
- help="configure terminal encoding to UTF-8 and enable ANSI escape code processing on Windows"
142
+ help=f"configure terminal encoding to {pys_sys.encoding} and enable ANSI escape code processing on Windows"
143
143
  )
144
144
 
145
145
  parser.add_argument(
@@ -216,7 +216,7 @@ if args.terminal:
216
216
 
217
217
  for fd in (sys.stdout, sys.stderr, sys.stdin):
218
218
  try:
219
- fd.reconfigure(encoding='utf-8')
219
+ fd.reconfigure(encoding=pys_sys.encoding)
220
220
  except:
221
221
  continue
222
222
 
@@ -28,7 +28,7 @@ pys_sys.builtin_module_names = tuple(
28
28
  for module in os.listdir(LIBRARIES_PATH)
29
29
  if get_module_candidate(os.path.join(LIBRARIES_PATH, module)) is not None
30
30
  )
31
- pys_sys.path = [LIBRARIES_PATH, SITE_PACKAGES_PATH]
31
+ pys_sys.path = [LIBRARIES_PATH]
32
32
  pys_sys.loading_modules = set()
33
33
  pys_sys.modules = {}
34
34
  pys_sys.interns = {}
@@ -51,6 +51,9 @@ pys_sys.ps1 = '>>> '
51
51
  pys_sys.ps2 = '... '
52
52
  pys_sys._is_gil_enabled = lambda : pys_sys.gil
53
53
 
54
+ if SITE_PACKAGES_PATH is not None:
55
+ pys_sys.path.append(SITE_PACKAGES_PATH)
56
+
54
57
  for name in (
55
58
  '_clear_internal_caches', '_is_immortal', '_is_interned', 'byteorder', 'exit', 'float_info', 'float_repr_style',
56
59
  'get_int_max_str_digits', 'getallocatedblocks', 'getdefaultencoding', 'getfilesystemencodeerrors',
@@ -1,10 +1,12 @@
1
1
  import os
2
+ import site
2
3
 
3
4
  PYSCRIPT_PATH = os.path.sep.join(__file__.split(os.path.sep)[:-2])
4
5
  CORE_PATH = os.path.join(PYSCRIPT_PATH, 'core')
5
6
  LIBRARIES_PATH = os.path.join(PYSCRIPT_PATH, 'lib')
6
7
  OTHER_PATH = os.path.join(PYSCRIPT_PATH, 'other')
7
- SITE_PACKAGES_PATH = os.path.join(PYSCRIPT_PATH, 'site-packages')
8
+ SITE_PACKAGES_PATH = None if (site_path := site.getusersitepackages()) is None else \
9
+ os.path.join(site_path, 'pyscript', 'site-packages')
8
10
  ICON_PATH = os.path.join(OTHER_PATH, 'PyScript.ico')
9
11
  GLOBAL_HISTORY_PATH = os.path.join(os.path.expanduser('~'), '.pyscript_history')
10
12
  CONFIGURATIONS_PATH = os.path.join(OTHER_PATH, 'configurations.json')
@@ -88,6 +88,20 @@ try:
88
88
  text.see('insert')
89
89
  return 'break'
90
90
 
91
+ def on_dedent(event=None):
92
+ text = self.text
93
+
94
+ if text.get('insert-1c', 'insert') == '\t':
95
+ text.delete('insert-1c', 'insert')
96
+ refresh_line_numbers()
97
+ return 'break'
98
+
99
+ if text.get('insert linestart', 'insert linestart +1c') == '\t':
100
+ text.delete('insert linestart', 'insert linestart +1c')
101
+ refresh_line_numbers()
102
+
103
+ return 'break'
104
+
91
105
  def on_enter(event=None):
92
106
  text = self.text
93
107
  if text.tag_ranges('sel'):
@@ -188,7 +202,10 @@ try:
188
202
  self.text.edit_modified(False)
189
203
 
190
204
  self.text.bind('<<Modified>>', on_modified)
191
- self.text.bind('<Return>', on_enter)
205
+ self.text.bind('<Control-Return>', on_enter)
206
+ self.text.bind('<Control-j>', on_enter)
207
+ self.text.bind('<Shift-Tab>', on_dedent)
208
+ self.text.bind('<ISO_Left_Tab>', on_dedent)
192
209
  self.text.bind('<Prior>', on_page_up)
193
210
  self.text.bind('<Next>', on_page_down)
194
211
  self.text.bind('<KeyRelease>', refresh_line_numbers)
@@ -138,6 +138,22 @@ try:
138
138
  line = buffer.document.current_line_before_cursor
139
139
  buffer.insert_text('\n' + line[:len(line) - len(line.lstrip())])
140
140
 
141
+ @key_bindings.add('s-tab', filter=on_edit, eager=True)
142
+ def _(event):
143
+ buffer = self.text.buffer
144
+ document = buffer.document
145
+
146
+ if document.char_before_cursor == '\t':
147
+ buffer.delete_before_cursor(1)
148
+ return
149
+
150
+ elif document.current_line.startswith('\t'):
151
+ line_start = document.translate_row_col_to_index(document.cursor_position_row, 0)
152
+ old_position = buffer.cursor_position
153
+ buffer.cursor_position = line_start
154
+ buffer.delete(1)
155
+ buffer.cursor_position = max(line_start, old_position - 1)
156
+
141
157
  @key_bindings.add('c-w', filter=on_edit, eager=True)
142
158
  def _(event):
143
159
  self.set_configuration('wrap', not self.get_configuration('wrap', False))
@@ -1,5 +1,5 @@
1
1
  from .cache import pys_sys
2
- from .constants import ENV_PYSCRIPT_WITH_GIL
2
+ from .constants import SITE_PACKAGES_PATH, ENV_PYSCRIPT_WITH_GIL
3
3
  from .context import PysContext
4
4
  from .position import PysPosition
5
5
  from .pystypes import PysFunction
@@ -8,8 +8,18 @@ from .utils.generic import is_environ
8
8
  from types import MethodType
9
9
  from typing import Any
10
10
 
11
+ import os
12
+
11
13
  wrapper_function = (MethodType, classmethod, staticmethod)
12
14
 
15
+ if SITE_PACKAGES_PATH is not None:
16
+ try:
17
+ if os.path.isfile(SITE_PACKAGES_PATH):
18
+ os.remove(SITE_PACKAGES_PATH)
19
+ os.makedirs(SITE_PACKAGES_PATH, exist_ok=True)
20
+ except:
21
+ pass
22
+
13
23
  GIL = pys_sys.gil = False
14
24
  if is_environ(ENV_PYSCRIPT_WITH_GIL):
15
25
  try:
@@ -28,7 +28,6 @@ BUILTIN_FUNCTIONS = frozenset(
28
28
  )
29
29
 
30
30
  try:
31
- # if pygments module already exists
32
31
  from pygments.lexer import RegexLexer, include, bygroups
33
32
  from pygments.style import Style
34
33
  from pygments.token import (
@@ -308,17 +308,19 @@ def visit_BinaryOperatorNode(node: PysBinaryOperatorNode, context: PysContext) -
308
308
  result._context = context
309
309
  result._position = node.position
310
310
  with result:
311
- return_right = True
312
311
 
313
312
  if otype == T_OR:
314
313
  if left:
315
314
  return result.success(left)
315
+ return_right = True
316
316
  elif otype == T_AND:
317
317
  if not left:
318
318
  return result.success(left)
319
+ return_right = True
319
320
  elif otype == T_NULLISH:
320
321
  if left is not None:
321
322
  return result.success(left)
323
+ return_right = True
322
324
  else:
323
325
  return_right = False
324
326
 
@@ -595,13 +597,13 @@ def visit_MatchNode(node: PysMatchNode, context: PysContext) -> PysRunTimeResult
595
597
  should_return = result.should_return
596
598
  ntarget = node.target
597
599
 
598
- compare = False
599
-
600
600
  if ntarget:
601
601
  target = register(get_visitor(ntarget.__class__)(ntarget, context))
602
602
  if should_return():
603
603
  return result
604
604
  compare = True
605
+ else:
606
+ compare = False
605
607
 
606
608
  for ncondition, nvalue in node.cases:
607
609
  condition = register(get_visitor(ncondition.__class__)(ncondition, context))
@@ -611,7 +613,7 @@ def visit_MatchNode(node: PysMatchNode, context: PysContext) -> PysRunTimeResult
611
613
  result._position = ncondition.position
612
614
  with result:
613
615
 
614
- if target == condition if compare else (True if condition else False):
616
+ if (target == condition) if compare else condition:
615
617
  value = register(get_visitor(nvalue.__class__)(nvalue, context))
616
618
  if should_return():
617
619
  return result
@@ -654,7 +656,6 @@ def visit_TryNode(node: PysTryNode, context: PysContext) -> PysRunTimeResult:
654
656
  failure(None)
655
657
 
656
658
  for (targets, tparameter), body in node.catches:
657
- handle_exception = True
658
659
  stop = False
659
660
 
660
661
  if targets:
@@ -683,6 +684,9 @@ def visit_TryNode(node: PysTryNode, context: PysContext) -> PysRunTimeResult:
683
684
  handle_exception = True
684
685
  break
685
686
 
687
+ else:
688
+ handle_exception = True
689
+
686
690
  if stop:
687
691
  break
688
692
 
@@ -274,6 +274,7 @@ class PysTernaryOperatorNode(PysNode):
274
274
  invalid: PysNode,
275
275
  style: Literal['general', 'pythonic']
276
276
  ) -> 'PysTernaryOperatorNode | PysNode':
277
+
277
278
  if (l_condition := _get_literal_value(condition)) is not undefined:
278
279
  return valid if l_condition else invalid
279
280
 
@@ -398,17 +399,15 @@ class PysStatementsNode(PysNode):
398
399
  return elements[0]
399
400
 
400
401
  new = []
401
- constant_nodes = {PysConstantNode, PysDebugNode, PysEllipsisNode}
402
- interrupt_nodes = {PysReturnNode, PysThrowNode, PysContinueNode, PysBreakNode}
403
402
 
404
403
  for node in elements:
405
- if node.__class__ in constant_nodes:
404
+ if node.__class__ in _constant_nodes:
406
405
  continue
407
406
  elif node.__class__ is PysStatementsNode:
408
407
  new.extend(node.elements)
409
408
  else:
410
409
  new.append(node)
411
- if node.__class__ in interrupt_nodes:
410
+ if node.__class__ in _interrupt_nodes:
412
411
  break
413
412
 
414
413
  self = super().__new__(cls, position)
@@ -510,12 +509,16 @@ class PysSwitchNode(PysNode):
510
509
  target: PysNode,
511
510
  cases: list[tuple[PysNode, PysNode]],
512
511
  default: PysNode | None
513
- ) -> 'PysSwitchNode':
512
+ ) -> 'PysSwitchNode | PysNode':
513
+ default = _optional_part(default)
514
+
515
+ if not (cases or default):
516
+ return target
514
517
 
515
518
  self = super().__new__(cls, position)
516
519
  setimuattr(self, 'target', target)
517
520
  setimuattr(self, 'cases', tuple(cases))
518
- setimuattr(self, 'default', _optional_part(default))
521
+ setimuattr(self, 'default', default)
519
522
  return self
520
523
 
521
524
  def __repr__(self) -> str:
@@ -532,12 +535,31 @@ class PysMatchNode(PysNode):
532
535
  target: PysNode | None,
533
536
  cases: list[tuple[PysNode, PysNode]],
534
537
  default: PysNode | None
535
- ) -> 'PysMatchNode':
538
+ ) -> 'PysMatchNode | PysNode':
539
+
540
+ if target and (l_target := _get_literal_value(target)) is not undefined:
541
+ new_cases = []
542
+
543
+ for condition, value in cases:
544
+ if (l_condition := _get_literal_value(condition)) is undefined:
545
+ new_cases.append((condition, value))
546
+ elif l_target == l_condition:
547
+ default = value
548
+ break
549
+
550
+ cases = new_cases
551
+ default = _optional_part(default, expression=True)
552
+
553
+ if not cases:
554
+ return default if default else PysConstantNode(position, None)
555
+
556
+ else:
557
+ default = _optional_part(default, expression=True)
536
558
 
537
559
  self = super().__new__(cls, position)
538
560
  setimuattr(self, 'target', target)
539
561
  setimuattr(self, 'cases', tuple(cases))
540
- setimuattr(self, 'default', _optional_part(default))
562
+ setimuattr(self, 'default', default)
541
563
  return self
542
564
 
543
565
  def __repr__(self) -> str:
@@ -602,8 +624,7 @@ class PysForNode(PysNode):
602
624
  def __new__(
603
625
  cls,
604
626
  position: PysPosition,
605
- header: tuple[PysNode | None, PysNode | None, PysNode | None] |
606
- tuple[PysNode, PysNode],
627
+ header: tuple[PysNode | None, PysNode | None, PysNode | None] | tuple[PysNode, PysNode],
607
628
  body: PysNode,
608
629
  else_: PysNode | None
609
630
  ) -> 'PysForNode':
@@ -628,12 +649,16 @@ class PysWhileNode(PysNode):
628
649
  condition: PysNode,
629
650
  body: PysNode,
630
651
  else_: PysNode | None
631
- ) -> 'PysWhileNode':
652
+ ) -> 'PysWhileNode | PysNode':
653
+ else_ = _optional_part(else_)
654
+
655
+ if (l_condition := _get_literal_value(condition)) is not undefined and not l_condition:
656
+ return else_ if else_ else PysStatementsNode(position, [])
632
657
 
633
658
  self = super().__new__(cls, position)
634
659
  setimuattr(self, 'condition', condition)
635
660
  setimuattr(self, 'body', body)
636
- setimuattr(self, 'else_', _optional_part(else_))
661
+ setimuattr(self, 'else_', else_)
637
662
  return self
638
663
 
639
664
  def __repr__(self) -> str:
@@ -770,7 +795,7 @@ class PysReturnNode(PysNode):
770
795
  @typecheck
771
796
  def __new__(cls, position: PysPosition, value: PysNode | None) -> 'PysReturnNode':
772
797
  self = super().__new__(cls, position)
773
- setimuattr(self, 'value', _optional_part(value))
798
+ setimuattr(self, 'value', _optional_part(value, expression=True))
774
799
  return self
775
800
 
776
801
  def __repr__(self) -> str:
@@ -855,6 +880,9 @@ class PysBreakNode(PysNode):
855
880
  def __repr__(self) -> Literal['Break()']:
856
881
  return 'Break()'
857
882
 
883
+ _constant_nodes = frozenset([PysConstantNode, PysDebugNode, PysEllipsisNode])
884
+ _interrupt_nodes = frozenset([PysReturnNode, PysThrowNode, PysContinueNode, PysBreakNode])
885
+
858
886
  def _get_literal_value(item: Any) -> Any | PysUndefined:
859
887
 
860
888
  if isinstance(item, (PysConstantNode, PysToken)):
@@ -886,9 +914,9 @@ def _get_literal_value(item: Any) -> Any | PysUndefined:
886
914
 
887
915
  return undefined
888
916
 
889
- def _optional_part(part: PysNode | None) -> PysNode | None:
917
+ def _optional_part(part: PysNode | None, *, expression: bool = False) -> PysNode | None:
890
918
  return None if (
919
+ (not expression and part.__class__ in _constant_nodes) or
891
920
  _get_literal_value(part) is None or
892
- (part.__class__ is PysStatementsNode and not part.elements) or
893
- (part.__class__ in (PysDebugNode, PysEllipsisNode))
921
+ (part.__class__ is PysStatementsNode and not part.elements)
894
922
  ) else part
@@ -1197,66 +1197,71 @@ class PysParser(Pys):
1197
1197
 
1198
1198
  self.skip(result)
1199
1199
 
1200
- if self.current_token.type != TOKENS['LEFT_CURLY']:
1201
- return result.failure(self.new_error("expected '{'"))
1200
+ cases = []
1201
+ default = None
1202
1202
 
1203
- left_bracket_token = self.current_token
1203
+ if self.current_token.type == TOKENS['SEMICOLON']:
1204
+ result.register_advancement()
1205
+ self.advance()
1204
1206
 
1205
- result.register_advancement()
1206
- self.advance()
1207
- self.skip(result)
1207
+ elif self.current_token.type == TOKENS['LEFT_CURLY']:
1208
+ left_bracket_token = self.current_token
1208
1209
 
1209
- cases = []
1210
- default = None
1210
+ result.register_advancement()
1211
+ self.advance()
1212
+ self.skip(result)
1211
1213
 
1212
- while True:
1214
+ while True:
1213
1215
 
1214
- if self.current_token.match(TOKENS['KEYWORD'], 'case'):
1215
- result.register_advancement()
1216
- self.advance()
1217
- self.skip(result)
1216
+ if self.current_token.match(TOKENS['KEYWORD'], 'case'):
1217
+ result.register_advancement()
1218
+ self.advance()
1219
+ self.skip(result)
1218
1220
 
1219
- case = result.register(self.walrus(), True)
1220
- if result.error:
1221
- return result
1221
+ case = result.register(self.walrus(), True)
1222
+ if result.error:
1223
+ return result
1222
1224
 
1223
- self.skip(result)
1225
+ self.skip(result)
1224
1226
 
1225
- if self.current_token.type != TOKENS['COLON']:
1226
- return result.failure(self.new_error("expected ':'"))
1227
+ if self.current_token.type != TOKENS['COLON']:
1228
+ return result.failure(self.new_error("expected ':'"))
1227
1229
 
1228
- result.register_advancement()
1229
- self.advance()
1230
+ result.register_advancement()
1231
+ self.advance()
1230
1232
 
1231
- body = result.register(self.statements())
1232
- if result.error:
1233
- return result
1233
+ body = result.register(self.statements())
1234
+ if result.error:
1235
+ return result
1234
1236
 
1235
- cases.append((case, body))
1237
+ cases.append((case, body))
1236
1238
 
1237
- elif self.current_token.match(TOKENS['KEYWORD'], 'default', 'else'):
1238
- result.register_advancement()
1239
- self.advance()
1240
- self.skip(result)
1239
+ elif self.current_token.match(TOKENS['KEYWORD'], 'default', 'else'):
1240
+ result.register_advancement()
1241
+ self.advance()
1242
+ self.skip(result)
1241
1243
 
1242
- if self.current_token.type != TOKENS['COLON']:
1243
- return result.failure(self.new_error("expected ':'"))
1244
+ if self.current_token.type != TOKENS['COLON']:
1245
+ return result.failure(self.new_error("expected ':'"))
1244
1246
 
1245
- result.register_advancement()
1246
- self.advance()
1247
+ result.register_advancement()
1248
+ self.advance()
1247
1249
 
1248
- default = result.register(self.statements())
1249
- if result.error:
1250
- return result
1250
+ default = result.register(self.statements())
1251
+ if result.error:
1252
+ return result
1251
1253
 
1252
- break
1254
+ break
1253
1255
 
1254
- else:
1255
- break
1256
+ else:
1257
+ break
1256
1258
 
1257
- self.close_bracket(result, left_bracket_token)
1258
- if result.error:
1259
- return result
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 '{'"))
1260
1265
 
1261
1266
  return result.success(
1262
1267
  PysSwitchNode(
@@ -461,7 +461,8 @@ def ce(context, position, a, b, *, rel_tol=1e-9, abs_tol=0):
461
461
  abs_tol: maximum difference for being considered "close", regardless of the magnitude of the input values.
462
462
  """
463
463
 
464
- if isinstance(a, real_complex_number) and isinstance(b, real_complex_number):
464
+ b_isinstance = isinstance
465
+ if b_isinstance(a, real_complex_number) and b_isinstance(b, real_complex_number):
465
466
  return isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol)
466
467
 
467
468
  result = _magic_method(context, position, a, '__ce__', b, rel_tol=rel_tol, abs_tol=abs_tol)
@@ -495,7 +496,8 @@ def nce(context, position, a, b, *, rel_tol=1e-9, abs_tol=0):
495
496
  abs_tol: maximum difference for being considered "close", regardless of the magnitude of the input values.
496
497
  """
497
498
 
498
- if isinstance(a, real_complex_number) and isinstance(b, real_complex_number):
499
+ b_isinstance = isinstance
500
+ if b_isinstance(a, real_complex_number) and b_isinstance(b, real_complex_number):
499
501
  return not isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol)
500
502
 
501
503
  result = _magic_method(context, position, a, '__nce__', b, rel_tol=rel_tol, abs_tol=abs_tol)
@@ -526,9 +528,10 @@ def increment(context, position, object):
526
528
  __increment__ method, which if unsuccessful will throw a TypeError.
527
529
  """
528
530
 
529
- if isinstance(object, real_number):
531
+ b_isinstance = isinstance
532
+ if b_isinstance(object, real_number):
530
533
  return object + 1
531
- elif isinstance(object, sequence):
534
+ elif b_isinstance(object, sequence):
532
535
  return tuple(_pyincrement(context, position, obj) for obj in object)
533
536
 
534
537
  result = _magic_method(context, position, object, '__increment__')
@@ -550,9 +553,10 @@ def decrement(context, position, object):
550
553
  call the __decrement__ method, which if unsuccessful will throw a TypeError.
551
554
  """
552
555
 
553
- if isinstance(object, real_number):
556
+ b_isinstance = isinstance
557
+ if b_isinstance(object, real_number):
554
558
  return object - 1
555
- elif isinstance(object, sequence):
559
+ elif b_isinstance(object, sequence):
556
560
  return tuple(_pydecrement(context, position, obj) for obj in object)
557
561
 
558
562
  result = _magic_method(context, position, object, '__decrement__')
@@ -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
@@ -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
- pyhelp(*args, **kwargs)
336
+ self._pyhelp(*args, **kwargs)