easycoder 251104.2__py2.py3-none-any.whl → 260110.1__py2.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.

Potentially problematic release.


This version of easycoder might be problematic. Click here for more details.

Files changed (60) hide show
  1. easycoder/__init__.py +5 -3
  2. easycoder/debugger/__init__.py +5 -0
  3. easycoder/debugger/ec_dbg_value_display copy.py +195 -0
  4. easycoder/debugger/ec_dbg_value_display.py +24 -0
  5. easycoder/debugger/ec_dbg_watch_list copy.py +219 -0
  6. easycoder/debugger/ec_dbg_watchlist.py +293 -0
  7. easycoder/debugger/ec_debug.py +1025 -0
  8. easycoder/ec_border.py +15 -11
  9. easycoder/ec_classes.py +487 -11
  10. easycoder/ec_compiler.py +81 -44
  11. easycoder/ec_condition.py +1 -1
  12. easycoder/ec_core.py +1044 -1090
  13. easycoder/ec_gclasses.py +236 -0
  14. easycoder/ec_graphics.py +1683 -0
  15. easycoder/ec_handler.py +18 -13
  16. easycoder/ec_keyboard.py +50 -50
  17. easycoder/ec_program.py +299 -156
  18. easycoder/ec_psutil.py +48 -0
  19. easycoder/ec_timestamp.py +2 -1
  20. easycoder/ec_value.py +65 -47
  21. easycoder/icons/exit.png +0 -0
  22. easycoder/icons/run.png +0 -0
  23. easycoder/icons/step.png +0 -0
  24. easycoder/icons/stop.png +0 -0
  25. easycoder/pre/README.md +3 -0
  26. easycoder/pre/__init__.py +17 -0
  27. easycoder/pre/debugger/__init__.py +5 -0
  28. easycoder/pre/debugger/ec_dbg_value_display copy.py +195 -0
  29. easycoder/pre/debugger/ec_dbg_value_display.py +24 -0
  30. easycoder/pre/debugger/ec_dbg_watch_list copy.py +219 -0
  31. easycoder/pre/debugger/ec_dbg_watchlist.py +293 -0
  32. easycoder/pre/debugger/ec_debug.py +1014 -0
  33. easycoder/pre/ec_border.py +67 -0
  34. easycoder/pre/ec_classes.py +470 -0
  35. easycoder/pre/ec_compiler.py +291 -0
  36. easycoder/pre/ec_condition.py +27 -0
  37. easycoder/pre/ec_core.py +2772 -0
  38. easycoder/pre/ec_gclasses.py +230 -0
  39. easycoder/{ec_pyside.py → pre/ec_graphics.py} +631 -496
  40. easycoder/pre/ec_handler.py +79 -0
  41. easycoder/pre/ec_keyboard.py +439 -0
  42. easycoder/pre/ec_program.py +557 -0
  43. easycoder/pre/ec_psutil.py +48 -0
  44. easycoder/pre/ec_timestamp.py +11 -0
  45. easycoder/pre/ec_value.py +124 -0
  46. easycoder/pre/icons/close.png +0 -0
  47. easycoder/pre/icons/exit.png +0 -0
  48. easycoder/pre/icons/run.png +0 -0
  49. easycoder/pre/icons/step.png +0 -0
  50. easycoder/pre/icons/stop.png +0 -0
  51. easycoder/pre/icons/tick.png +0 -0
  52. {easycoder-251104.2.dist-info → easycoder-260110.1.dist-info}/METADATA +11 -1
  53. easycoder-260110.1.dist-info/RECORD +58 -0
  54. easycoder/ec_debug.py +0 -464
  55. easycoder-251104.2.dist-info/RECORD +0 -20
  56. /easycoder/{close.png → icons/close.png} +0 -0
  57. /easycoder/{tick.png → icons/tick.png} +0 -0
  58. {easycoder-251104.2.dist-info → easycoder-260110.1.dist-info}/WHEEL +0 -0
  59. {easycoder-251104.2.dist-info → easycoder-260110.1.dist-info}/entry_points.txt +0 -0
  60. {easycoder-251104.2.dist-info → easycoder-260110.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,67 @@
1
+ import os
2
+ from PySide6.QtWidgets import QWidget
3
+ from PySide6.QtGui import QPixmap, QPainter
4
+ from PySide6.QtCore import Qt, Signal, QRect
5
+
6
+ class Border(QWidget):
7
+ tickClicked = Signal()
8
+ closeClicked = Signal()
9
+
10
+ def __init__(self):
11
+ super().__init__()
12
+ self._size = 40
13
+ self.setFixedHeight(self._size)
14
+ self._drag_active = False
15
+ self._drag_start_pos = None
16
+ self._tick: QPixmap = QPixmap()
17
+ self._close_icon: QPixmap = QPixmap()
18
+
19
+ def paintEvent(self, event):
20
+ painter = QPainter(self)
21
+ painter.setRenderHint(QPainter.RenderHint.Antialiasing)
22
+ # Draw the tick icon
23
+ self._tick = QPixmap(f'{os.path.dirname(os.path.abspath(__file__))}/icons/tick.png').scaled(
24
+ self._size, self._size, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
25
+ x = 0
26
+ y = 0
27
+ painter.drawPixmap(x, y, self._tick)
28
+ # Draw the close icon
29
+ self._close_icon = QPixmap(f'{os.path.dirname(os.path.abspath(__file__))}/icons/close.png').scaled(
30
+ self._size, self._size, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
31
+ x = self.width() - self._close_icon.width()
32
+ y = 0
33
+ painter.drawPixmap(x, y, self._close_icon)
34
+
35
+ def mousePressEvent(self, event):
36
+ # Tick icon
37
+ x = 0
38
+ y = 0
39
+ tickRect = self._tick.rect().translated(x, y)
40
+ # Close icon
41
+ x = self.width() - self._close_icon.width()
42
+ y = 0
43
+ closeRect = self._close_icon.rect().translated(x, y)
44
+ if tickRect.contains(event.pos()):
45
+ self.tickClicked.emit()
46
+ if closeRect.contains(event.pos()):
47
+ self.closeClicked.emit()
48
+ elif QRect(0, 0, self.width(), self.height()).contains(event.pos()):
49
+ if hasattr(self.window().windowHandle(), 'startSystemMove'):
50
+ self.window().windowHandle().startSystemMove()
51
+ else:
52
+ self._drag_active = True
53
+ self._drag_start_pos = event.globalPosition().toPoint()
54
+ self._dialog_start_pos = self.window().pos()
55
+ else:
56
+ super().mousePressEvent(event)
57
+
58
+ def mouseMoveEvent(self, event):
59
+ if self._drag_active:
60
+ delta = event.globalPosition().toPoint() - self._drag_start_pos
61
+ self.window().move(self._dialog_start_pos + delta)
62
+ else:
63
+ super().mouseMoveEvent(event)
64
+
65
+ def mouseReleaseEvent(self, event):
66
+ self._drag_active = False
67
+ super().mouseReleaseEvent(event)
@@ -0,0 +1,470 @@
1
+ import sys, paramiko, json
2
+ from typing import Optional, Any
3
+
4
+ class FatalError(BaseException):
5
+ def __init__(self, compiler, message):
6
+ compiler.showWarnings()
7
+ lino = compiler.tokens[compiler.index].lino
8
+ script = compiler.script.lines[lino].strip()
9
+ print(f'Compile error in {compiler.program.name} at line {lino + 1} ({script}):\n-> {message}')
10
+ sys.exit()
11
+
12
+ class NoValueError(FatalError):
13
+ def __init__(self, compiler, record):
14
+ super().__init__(compiler, f'Variable {record["name"]} does not hold a value')
15
+
16
+ class RuntimeAssertionError:
17
+ def __init__(self, program, msg=None):
18
+ code = program.code[program.pc]
19
+ lino = code['lino']
20
+ message = f'Assertion Error in {program.name} at line {lino + 1}'
21
+ if msg != None:
22
+ message += f': {msg}'
23
+ print(message)
24
+ sys.exit()
25
+
26
+ class RuntimeError(BaseException):
27
+ def __init__(self, program, message):
28
+ if program == None:
29
+ sys.exit(f'Runtime Error: {message}')
30
+ else:
31
+ code = program.code[program.pc]
32
+ lino = code['lino']
33
+ script = program.script.lines[lino].strip()
34
+ print(f'Runtime Error in {program.name} at line {lino + 1} ({script}):\n-> {message}')
35
+ sys.exit()
36
+
37
+ class NoValueRuntimeError(RuntimeError):
38
+ def __init__(self, program, record):
39
+ super().__init__(program, 'Variable {record["name"]} does not hold a value')
40
+
41
+ class RuntimeWarning:
42
+ def __init__(self, program, message):
43
+ if program == None:
44
+ print(f'Runtime Warning: {message}')
45
+ else:
46
+ code = program.code[program.pc]
47
+ lino = code['lino']
48
+ script = program.script.lines[lino].strip()
49
+ print(f'Runtime Warning in {program.name} at line {lino + 1} ({script}): {message}')
50
+
51
+ class Script:
52
+ def __init__(self, source):
53
+ self.lines = source.splitlines()
54
+ self.tokens = []
55
+
56
+ class Token:
57
+ def __init__(self, lino, token):
58
+ self.lino = lino
59
+ self.token = token
60
+
61
+ ###############################################################################
62
+ # This is the set of generic EasyCoder objects (values and variables)
63
+
64
+ ###############################################################################
65
+ # A multipurpose value object. Holds a single value, with domain and type information
66
+ class ECValue():
67
+ def __init__(self, domain: Optional[str] = 'core', type: Optional[str] = None,
68
+ content: Any = None, name: Optional[str] = None):
69
+ object.__setattr__(self, 'domain', domain)
70
+ object.__setattr__(self, 'type', type)
71
+ object.__setattr__(self, 'content', content)
72
+ object.__setattr__(self, 'name', name)
73
+ object.__setattr__(self, 'properties', {})
74
+ object.__setattr__(self, 'locked', False)
75
+ object.__setattr__(self, '_attrs', {}) # Store dynamic attributes
76
+
77
+ def __setattr__(self, name: str, value: Any) -> None:
78
+ """Allow setting any attribute dynamically."""
79
+ if name in ('domain', 'type', 'content', 'name', 'properties', 'locked', '_attrs'):
80
+ object.__setattr__(self, name, value)
81
+ else:
82
+ # Store dynamic attributes in _attrs dict
83
+ self._attrs[name] = value
84
+
85
+ def __getattr__(self, name: str) -> Any:
86
+ """Retrieve dynamic attributes or return None if not found."""
87
+ if name == '_attrs':
88
+ return object.__getattribute__(self, '_attrs')
89
+ return self._attrs.get(name)
90
+
91
+ def setDomain(self, domain):
92
+ self.domain = domain
93
+
94
+ def getDomain(self):
95
+ return self.domain
96
+
97
+ def setType(self, type):
98
+ self.type = type
99
+
100
+ def getType(self):
101
+ return self.type
102
+
103
+ def setContent(self, content):
104
+ self.content = content
105
+
106
+ def getContent(self):
107
+ return self.content
108
+
109
+ def setValue(self, type=None, content=None):
110
+ self.type = type
111
+ self.content = content
112
+
113
+ def setProperty(self, key, value):
114
+ self.properties[key] = value
115
+
116
+ def getProperty(self, key):
117
+ return self.properties.get(key, None)
118
+
119
+ def setName(self, name):
120
+ self.name = name
121
+
122
+ def getName(self):
123
+ return self.name
124
+
125
+ def lock(self):
126
+ self.locked = True
127
+
128
+ def isLocked(self):
129
+ return self.locked
130
+
131
+ ###############################################################################
132
+ # The base class for all EasyCoder variable types
133
+ class ECObject():
134
+ def __init__(self):
135
+ self.locked: bool = False
136
+ self.elements: int = 0
137
+ self.index: Optional[int] = None
138
+ self.values: Optional[list] = None
139
+ self.name: Optional[str] = None
140
+ self.properties = {}
141
+
142
+ # Set the index for the variable
143
+ def setIndex(self, index: int) -> None:
144
+ self.index = index
145
+
146
+ # Get the index for the variable
147
+ def getIndex(self):
148
+ return self.index
149
+
150
+ # Lock the variable
151
+ def setLocked(self):
152
+ self.locked = True
153
+
154
+ # Check if the variable is locked
155
+ def isLocked(self):
156
+ return self.locked
157
+
158
+ # Set the value at the current index
159
+ def setValue(self, value):
160
+ if self.values is None:
161
+ self.index = 0
162
+ self.elements = 1
163
+ self.values = [None]
164
+ if isinstance(value, ECValue): value.setName(self.name)
165
+ self.values[self.index] = value # type: ignore
166
+
167
+ # Get the value at the current index
168
+ def getValue(self):
169
+ if self.values is None: return None
170
+ return self.values[self.index] # type: ignore
171
+
172
+ # Get all the values
173
+ def getValues(self):
174
+ return self.values
175
+
176
+ # Set the number of elements in the variable
177
+ def setElements(self, elements):
178
+ if self.elements == 0:
179
+ self.values = [None] * elements
180
+ self.elements = elements
181
+ self.index = 0
182
+ if elements == self.elements:
183
+ pass
184
+ elif elements > self.elements:
185
+ self.values.extend([None] * (elements - self.elements)) # pyright: ignore[reportOptionalMemberAccess]
186
+ else:
187
+ del self.values[elements:] # pyright: ignore[reportOptionalSubscript]
188
+ self.index = 0
189
+ self.elements = elements
190
+
191
+ # Get the number of elements in the variable
192
+ def getElements(self):
193
+ return self.elements
194
+
195
+ # Check if the object has a runtime value. Default is False
196
+ def hasRuntimeValue(self):
197
+ return False
198
+
199
+ # Check if the object is mutable. Default is False
200
+ def isMutable(self):
201
+ return False
202
+
203
+ # Check if the object is clearable
204
+ def isClearable(self):
205
+ return False
206
+
207
+ # Get the content of the value at the current index
208
+ def getContent(self):
209
+ if not self.hasRuntimeValue(): return None
210
+ v = self.getValue()
211
+ if v is None: return None
212
+ return v.getContent()
213
+
214
+ # Get the type of the value at the current index
215
+ def getType(self):
216
+ if not self.hasRuntimeValue(): return None
217
+ v = self.getValue()
218
+ if v is None: return None
219
+ return v.getType()
220
+
221
+ # Check if the object is empty. Default is True
222
+ def isEmpty(self):
223
+ return True
224
+
225
+ # Set the name of the object
226
+ def setName(self, name):
227
+ self.name = name
228
+
229
+ # Get the name of the object
230
+ def getName(self):
231
+ return self.name
232
+
233
+ # Set a specific property on the object
234
+ def setProperty(self, name, value):
235
+ self.properties[name] = value
236
+
237
+ # Check if the object has a specific property
238
+ def hasProperty(self, name):
239
+ return name in self.properties
240
+
241
+ # Get a specific property
242
+ def getProperty(self, name):
243
+ return self.properties[name]
244
+
245
+ ###############################################################################
246
+ # A generic variable object that can hold a mutable value
247
+ class ECValueHolder(ECObject):
248
+ def __init__(self):
249
+ super().__init__()
250
+
251
+ # Set the content of the value at the current index
252
+ def setContent(self, content):
253
+ if self.values is None:
254
+ self.index = 0
255
+ self.elements = 1
256
+ self.values = [None]
257
+ self.values[self.index] = content # type: ignore
258
+
259
+ # Set the value to a given ECValue
260
+ def setValue(self, value):
261
+ if self.values is None:
262
+ self.index = 0
263
+ self.elements = 1
264
+ self.values = [None]
265
+ if self.index >= self.elements: raise RuntimeError(None, 'Index out of range') # type: ignore
266
+ self.values[self.index] = value # type: ignore
267
+
268
+ # Report if the object is clearable
269
+ def isClearable(self):
270
+ return True
271
+
272
+ # This object has a runtime value
273
+ def hasRuntimeValue(self):
274
+ return True
275
+
276
+ # This object is mutable.
277
+ def isMutable(self):
278
+ return True
279
+
280
+ # Reset the object to empty state
281
+ def reset(self):
282
+ self.setValue(ECValue(content=None))
283
+
284
+ ###############################################################################
285
+ # A string or int variable
286
+ class ECVariable(ECValueHolder):
287
+ def __init__(self):
288
+ super().__init__()
289
+
290
+ # Reset the object to an empty string
291
+ def reset(self):
292
+ self.setValue(ECValue(type=str, content=''))
293
+
294
+ # Set the value to a given ECValue
295
+ def setValue(self, value):
296
+ if value.getType() not in (str, int, float, bool):
297
+ raise RuntimeError(None, 'ECVariable can only hold str, int, float, or bool values') # type: ignore
298
+ super().setValue(value)
299
+
300
+ ###############################################################################
301
+ # A dictionary variable
302
+ class ECDictionary(ECValueHolder):
303
+ def __init__(self):
304
+ super().__init__()
305
+ self.reset()
306
+
307
+ # Reset the object to empty state
308
+ def reset(self):
309
+ self.setValue(ECValue(content={}))
310
+
311
+ # Set the value to an ECValue
312
+ def setValue(self, value):
313
+ varType = value.getType()
314
+ if varType in (str, 'dict'):
315
+ content = value.getContent()
316
+ if varType == str:
317
+ try:
318
+ if content in ('', None): content = {}
319
+ else: content = json.loads(content)
320
+ except:
321
+ raise RuntimeError(None, 'ECDictionary string value is not valid JSON') # type: ignore
322
+ elif varType == None:
323
+ content = {}
324
+ else:
325
+ raise RuntimeError(None, 'ECDictionary can only hold dict values or None') # type: ignore
326
+ super().setValue(content)
327
+
328
+ def getValue(self):
329
+ return super().getValue()
330
+
331
+ # Set an entry in the dictionary
332
+ def setEntry(self, key, value):
333
+ content = self.getValue()
334
+ if content is None:
335
+ return
336
+ if isinstance(value, str):
337
+ try:
338
+ value = json.loads(value)
339
+ except Exception:
340
+ pass
341
+ content[key] = value # type: ignore
342
+
343
+ # Test if an entry exists in the dictionary
344
+ def hasEntry(self, key):
345
+ content = self.getValue()
346
+ if content is None:
347
+ return False
348
+ return key in content
349
+
350
+ # Get an entry from the dictionary
351
+ def getEntry(self, key):
352
+ content = self.getValue()
353
+ if content is None:
354
+ return None
355
+ return content.get(key, None)
356
+
357
+ # Delete an entry from the dictionary
358
+ def deleteEntry(self, key):
359
+ content = self.getValue()
360
+ if content is None:
361
+ return
362
+ if key in content:
363
+ del content[key]
364
+
365
+ # Get the keys of the dictionary
366
+ def keys(self):
367
+ content = self.getValue()
368
+ if content is None:
369
+ return []
370
+ return list(content.keys())
371
+
372
+ # Check if the dictionary is empty
373
+ def isEmpty(self):
374
+ return len(self.keys()) == 0
375
+
376
+ ###############################################################################
377
+ # A list variable
378
+ class ECList(ECValueHolder):
379
+ def __init__(self):
380
+ super().__init__()
381
+ self.reset()
382
+
383
+ # Reset the object to empty state
384
+ def reset(self):
385
+ self.setValue(ECValue(content=[]))
386
+
387
+ # Set the value to a given ECValue
388
+ def setValue(self, value):
389
+ if value.getType() not in ('list', None):
390
+ raise RuntimeError(None, 'ECList can only hold list values or None') # type: ignore
391
+ super().setValue(value)
392
+
393
+ # Add an item to the list
394
+ def addItem(self, item):
395
+ content = self.getContent()
396
+ if content is None:
397
+ return
398
+ if isinstance(item, str):
399
+ try:
400
+ item = json.loads(item)
401
+ except Exception:
402
+ pass
403
+ content.append(item) # type: ignore
404
+
405
+ # Return the number of items in the list
406
+ def getItemCount(self):
407
+ content = self.getContent()
408
+ if content is None:
409
+ return 0
410
+ return len(content)
411
+
412
+ # Get an item from the list
413
+ def getItem(self, index):
414
+ content = self.getContent()
415
+ if content is None:
416
+ return None
417
+ return content[index]
418
+
419
+ # Check if the list is empty
420
+ def isEmpty(self):
421
+ return self.getItemCount() == 0
422
+
423
+ ###############################################################################
424
+ # A file variable
425
+ class ECFile(ECObject):
426
+ def __init__(self):
427
+ super().__init__()
428
+
429
+ ###############################################################################
430
+ # An SSH variable
431
+ class ECSSH(ECObject):
432
+ def __init__(self):
433
+ super().__init__()
434
+
435
+ # Set up the SSH connection
436
+ def setup(self, host=None, user=None, password=None):
437
+ ssh = paramiko.SSHClient()
438
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
439
+ try:
440
+ ssh.connect(host, username=user, password=password, timeout=10) # type: ignore
441
+ self.setValue(ssh)
442
+ self.sftp = ssh.open_sftp()
443
+ return True
444
+ except:
445
+ return False
446
+
447
+ # Get the SFTP client
448
+ def getSFTP(self):
449
+ return self.sftp
450
+
451
+ ###############################################################################
452
+ # A stack variable
453
+ class ECStack(ECObject):
454
+
455
+ def __init__(self):
456
+ super().__init__()
457
+ self.values: Optional[list[list[Any]]] = None # List of stacks, each holding any type
458
+
459
+ def push(self, item: Any) -> None:
460
+ if self.values is None:
461
+ self.index = 0
462
+ self.elements = 1
463
+ self.values = [[]]
464
+ assert self.index is not None # Type narrowing: index is always set when values exists
465
+ self.values[self.index].append(item)
466
+
467
+ def pop(self) -> Any:
468
+ if self.values is None or self.index is None or self.values[self.index] is None or len(self.values[self.index]) == 0:
469
+ return None
470
+ return self.values[self.index].pop()