easycoder 251104.1__py2.py3-none-any.whl → 260108.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 +6 -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 +494 -7
  10. easycoder/ec_compiler.py +82 -44
  11. easycoder/ec_condition.py +1 -1
  12. easycoder/ec_core.py +1043 -1089
  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_mqtt.py +249 -0
  18. easycoder/ec_program.py +313 -152
  19. easycoder/ec_psutil.py +48 -0
  20. easycoder/ec_timestamp.py +2 -1
  21. easycoder/ec_value.py +65 -47
  22. easycoder/icons/exit.png +0 -0
  23. easycoder/icons/run.png +0 -0
  24. easycoder/icons/step.png +0 -0
  25. easycoder/icons/stop.png +0 -0
  26. easycoder/pre/README.md +3 -0
  27. easycoder/pre/__init__.py +17 -0
  28. easycoder/pre/debugger/__init__.py +5 -0
  29. easycoder/pre/debugger/ec_dbg_value_display copy.py +195 -0
  30. easycoder/pre/debugger/ec_dbg_value_display.py +24 -0
  31. easycoder/pre/debugger/ec_dbg_watch_list copy.py +219 -0
  32. easycoder/pre/debugger/ec_dbg_watchlist.py +293 -0
  33. easycoder/pre/debugger/ec_debug.py +1014 -0
  34. easycoder/pre/ec_border.py +67 -0
  35. easycoder/pre/ec_classes.py +470 -0
  36. easycoder/pre/ec_compiler.py +291 -0
  37. easycoder/pre/ec_condition.py +27 -0
  38. easycoder/pre/ec_core.py +2772 -0
  39. easycoder/pre/ec_gclasses.py +230 -0
  40. easycoder/{ec_pyside.py → pre/ec_graphics.py} +631 -494
  41. easycoder/pre/ec_handler.py +79 -0
  42. easycoder/pre/ec_keyboard.py +439 -0
  43. easycoder/pre/ec_program.py +557 -0
  44. easycoder/pre/ec_psutil.py +48 -0
  45. easycoder/pre/ec_timestamp.py +11 -0
  46. easycoder/pre/ec_value.py +124 -0
  47. easycoder/pre/icons/close.png +0 -0
  48. easycoder/pre/icons/exit.png +0 -0
  49. easycoder/pre/icons/run.png +0 -0
  50. easycoder/pre/icons/step.png +0 -0
  51. easycoder/pre/icons/stop.png +0 -0
  52. easycoder/pre/icons/tick.png +0 -0
  53. {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/METADATA +11 -1
  54. easycoder-260108.1.dist-info/RECORD +59 -0
  55. easycoder-251104.1.dist-info/RECORD +0 -19
  56. /easycoder/{close.png → icons/close.png} +0 -0
  57. /easycoder/{tick.png → icons/tick.png} +0 -0
  58. {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/WHEEL +0 -0
  59. {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/entry_points.txt +0 -0
  60. {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/licenses/LICENSE +0 -0
easycoder/ec_program.py CHANGED
@@ -1,7 +1,16 @@
1
- import time, json, sys
1
+ import time, sys, json
2
2
  from copy import deepcopy
3
3
  from collections import deque
4
- from .ec_classes import Script, Token, FatalError, RuntimeError, Object
4
+ from .ec_classes import (
5
+ Script,
6
+ Token,
7
+ FatalError,
8
+ RuntimeError,
9
+ NoValueRuntimeError,
10
+ ECObject,
11
+ ECValue,
12
+ normalize_type
13
+ )
5
14
  from .ec_compiler import Compiler
6
15
  from .ec_core import Core
7
16
  import importlib
@@ -16,20 +25,25 @@ def flush():
16
25
 
17
26
  class Program:
18
27
 
19
- def __init__(self, argv):
28
+ def __init__(self, arg):
20
29
  global queue
21
30
  print(f'EasyCoder version {version("easycoder")}')
22
- if len(argv) == 0:
31
+ if len(arg) == 0:
23
32
  print('No script supplied')
24
33
  exit()
25
- if argv in ['-v', '--version']: return
26
- scriptName = argv
34
+ if arg in ['-v', '--version']: return
35
+ if arg[0:6] == 'debug ':
36
+ print('Debug mode requested')
37
+ self.scriptName = arg[6:]
38
+ self.debugging = True
39
+ else:
40
+ self.scriptName = arg
41
+ self.debugging = False
27
42
 
28
- f = open(scriptName, 'r')
43
+ f = open(self.scriptName, 'r')
29
44
  source = f.read()
30
45
  f.close()
31
46
  queue = deque()
32
- self.argv = argv
33
47
  self.domains = []
34
48
  self.domainIndex = {}
35
49
  self.name = '<anon>'
@@ -38,25 +52,35 @@ class Program:
38
52
  self.symbols = {}
39
53
  self.onError = 0
40
54
  self.debugStep = False
55
+ self.debugSkip = False
41
56
  self.stack = []
42
57
  self.script = Script(source)
43
58
  self.compiler = Compiler(self)
59
+ self.object = ECObject()
44
60
  self.value = self.compiler.value
45
61
  self.condition = self.compiler.condition
46
62
  self.graphics = None
63
+ self.psutil = None
47
64
  self.useClass(Core)
48
- self.externalControl = False
49
65
  self.ticker = 0
50
- self.running = True
66
+ self.graphicsRunning = False
67
+ self.debugger = None
68
+ self.running = False
69
+ self.parent = None
70
+ self.message = None
71
+ self.onMessagePC = 0
72
+ self.breakpoint = False
51
73
 
52
74
  # This is called at 10msec intervals by the GUI code
53
75
  def flushCB(self):
54
76
  self.ticker += 1
77
+ # if self.ticker % 1000 == 0: print(f'GUI Tick {self.ticker}')
55
78
  flush()
56
79
 
57
80
  def start(self, parent=None, module = None, exports=[]):
58
81
  self.parent = parent
59
82
  self.exports = exports
83
+ if self.debugging: self.useGraphics()
60
84
  if module != None:
61
85
  module['child'] = self
62
86
  startCompile = time.time()
@@ -69,7 +93,7 @@ class Program:
69
93
  f'{round((finishCompile - startCompile) * 1000)} ms')
70
94
  for name in self.symbols.keys():
71
95
  record = self.code[self.symbols[name]]
72
- if name[-1] != ':' and not record['used']:
96
+ if name[-1] != ':' and not 'used' in record:
73
97
  print(f'Variable "{name}" not used')
74
98
  else:
75
99
  print(f'Run {self.name}')
@@ -78,13 +102,44 @@ class Program:
78
102
  self.compiler.showWarnings()
79
103
 
80
104
  # If this is the main script and there's no graphics, run a main loop
81
- if parent == None and self.externalControl == False:
82
- while True:
105
+ if parent == None:
106
+ while not self.graphicsRunning:
83
107
  if self.running == True:
84
108
  flush()
85
109
  time.sleep(0.01)
86
110
  else:
87
111
  break
112
+
113
+ # Use the graphics module
114
+ def useGraphics(self):
115
+ if self.graphics == None:
116
+ print('Loading graphics module')
117
+ from .ec_graphics import Graphics
118
+ self.graphics = Graphics
119
+ self.useClass(Graphics)
120
+ return True
121
+
122
+ # Use the mqtt module
123
+ def useMQTT(self):
124
+ if self.psutil == None:
125
+ print('Loading mqtt module')
126
+ from .ec_mqtt import MQTT
127
+ self.psutil = MQTT
128
+ self.useClass(MQTT)
129
+ return True
130
+
131
+ # Use the psutil module
132
+ def usePSUtil(self):
133
+ if self.psutil == None:
134
+ print('Loading psutil module')
135
+ from .ec_psutil import PSUtil
136
+ self.psutil = PSUtil
137
+ self.useClass(PSUtil)
138
+ return True
139
+
140
+ # Indicate that graphics are running
141
+ def startGraphics(self):
142
+ self.graphicsRunning = True
88
143
 
89
144
  # Import a plugin
90
145
  def importPlugin(self, source):
@@ -109,118 +164,225 @@ class Program:
109
164
  self.domains.append(handler)
110
165
  self.domainIndex[handler.getName()] = handler
111
166
 
167
+ # This is the runtime callback for event handlers
168
+ def callback(self, item, record, goto):
169
+ object = self.getObject(record)
170
+ values = object.getValues() # type: ignore
171
+ for i, v in enumerate(values):
172
+ if isinstance(v, ECValue): v = v.getContent()
173
+ if v == item:
174
+ object.setIndex(i) # type: ignore
175
+ self.run(goto)
176
+ return
177
+
178
+ # Ensure the program is running
179
+ def ensureRunning(self):
180
+ if not self.running:
181
+ raise RuntimeError(self, 'Improper use of runtime function')
182
+
183
+ # Ensure the program is not running
184
+ def ensureNotRunning(self):
185
+ if self.running:
186
+ raise RuntimeError(self, 'Improper use of non-runtime function')
187
+
112
188
  # Get the domain list
113
189
  def getDomains(self):
114
190
  return self.domains
115
-
116
- def getSymbolRecord(self, name):
191
+
192
+ def isSymbol(self, name):
193
+ return name in self.symbols
194
+
195
+ # Get the symbol record for a given name
196
+ def getVariable(self, name):
197
+ self.ensureRunning()
198
+ if isinstance(name, dict): name = name['name']
117
199
  try:
118
200
  target = self.code[self.symbols[name]]
119
- if target['import'] != None:
201
+ if 'import' in target:
120
202
  target = target['import']
121
203
  return target
122
204
  except:
123
205
  RuntimeError(self, f'Unknown symbol \'{name}\'')
206
+
207
+ # Get the object represented by a symbol record
208
+ def getObject(self, record):
209
+ if isinstance(record, dict) and 'object' in record:
210
+ return record['object']
211
+ return record
212
+
213
+ # Check if an object is an instance of a given class
214
+ # This can either be variable record (a dict) or an instance of ECObject
215
+ def isObjectType(self, object, classes):
216
+ if isinstance(object, dict) and 'object' in object and isinstance(object['object'], ECObject):
217
+ object = object['object']
218
+ return isinstance(object, classes)
219
+
220
+ # Check if the object is an instance of one of a set of classes. Compile and runtime
221
+ def checkObjectType(self, object, classes):
222
+ if isinstance(object, dict): return
223
+ if not isinstance(object, classes):
224
+ if isinstance(classes, tuple):
225
+ class_names = ", ".join([c.__name__ for c in classes])
226
+ message = f"Variable {object.name} should be one of {class_names}"
227
+ else:
228
+ class_names = classes.__name__
229
+ message = f"Variable {object.name} should be {class_names}"
230
+ if self.running:
231
+ raise RuntimeError(self, message)
232
+ else:
233
+ raise FatalError(self.compiler, message)
234
+
235
+ # Get the inner (non-EC) object from a name, record or object
236
+ def getInnerObject(self, object):
237
+ if isinstance(object, dict): object = object['object']
238
+ elif isinstance(object, str):
239
+ record = self.getVariable(object) # type: ignore
240
+ object = self.getObject(record) # type: ignore
241
+ value = object.getValue() # type: ignore
242
+ if isinstance(value, ECValue) and value.getType() == 'object':
243
+ return value.getContent()
244
+ else: return value
124
245
 
125
- def doValue(self, value):
126
- if value == None:
127
- RuntimeError(self, f'Undefined value (variable not initialized?)')
128
-
246
+ def constant(self, content, numeric):
129
247
  result = {}
130
- valType = value['type']
131
- if valType in ['boolean', 'int', 'text', 'object']:
132
- result = value
248
+ result['type'] = int if numeric else str
249
+ result['content'] = content
250
+ return result
251
+
252
+ # Test if an item is a string or a number
253
+ def getItemType(self, value):
254
+ return int if isinstance(value, int) else str
255
+
256
+ # Get the value of an item that may be an ECValue or a raw value. Return as an ECValue
257
+ def getValueOf(self, item):
258
+ value = ECValue()
259
+ if isinstance(item, ECValue):
260
+ if item.getType() == 'object':
261
+ return item.getContent()
262
+ else: value = item
263
+ else:
264
+ varType = type(item).__name__
265
+ if varType == 'int': value.setValue(type=int, content=item)
266
+ elif varType == 'str': value.setValue(type=str, content=item)
267
+ elif varType == 'bool': value.setValue(type=bool, content=item)
268
+ elif varType == 'float': value.setValue(type=str, content=str(item))
269
+ elif varType == 'list': value.setValue(type=list, content=item)
270
+ elif varType == 'dict': value.setValue(type=dict, content=item)
271
+ else: value.setValue(type=None, content=None)
272
+ return value
273
+
274
+ # Runtime function to evaluate an ECObject or ECValue. Returns another ECValue
275
+ # This function may be called recursively by value handlers.
276
+ def evaluate(self, item):
277
+ self.ensureRunning()
278
+ if isinstance(item, ECObject):
279
+ value = item.getValue()
280
+ if value == None:
281
+ raise RuntimeError(self, f'Symbol {item.getName()} not initialized')
282
+ else: value = item
283
+ try:
284
+ valType = normalize_type(value.getType()) # type: ignore
285
+ except:
286
+ RuntimeError(self, 'Value does not hold a valid ECValue')
287
+ result = ECValue(type=valType)
288
+
289
+ if valType in ('str', 'int', 'bool', 'list', 'dict', None):
290
+ # Simple value - just return the content
291
+ result.setContent(value.getContent()) # type: ignore
292
+
293
+ elif valType == 'object':
294
+ # Object other than ECVariable
295
+ record = self.getVariable(value.getName())
296
+ object = self.getObject(record) # type: ignore
297
+ result = object.getContent() # type: ignore
298
+
299
+ elif valType == 'symbol': # type: ignore
300
+ # If it's a symbol, get its value
301
+ record = self.getVariable(value.getContent()) # type: ignore
302
+ if not 'object' in record: return None # type: ignore
303
+ variable = self.getObject(record) # type: ignore
304
+ result = variable.getValue() # type: ignore
305
+ if isinstance(result, ECValue): return self.evaluate(result)
306
+ if isinstance(result, ECObject): return result.getValue()
307
+ if isinstance(result, dict) or isinstance(result, list):
308
+ return result
309
+ # See if one of the domains can handle this value
310
+ value = result
311
+ result = None
312
+ for domain in self.domains:
313
+ result = domain.getUnknownValue(value)
314
+ if result != None: break
315
+
133
316
  elif valType == 'cat':
317
+ # Handle concatenation
134
318
  content = ''
135
- for part in value['value']:
136
- val = self.doValue(part)
137
- if val == None:
138
- val = ''
139
- if val != '':
140
- val = str(val['content'])
141
- if val == None:
142
- val = ''
143
- content += val
144
- result['type'] = 'text'
145
- result['content'] = content
146
- elif valType == 'symbol':
147
- name = value['name']
148
- symbolRecord = self.getSymbolRecord(name)
149
- # if symbolRecord['hasValue']:
150
- handler = self.domainIndex[symbolRecord['domain']].valueHandler('symbol')
151
- result = handler(symbolRecord)
152
- # else:
153
- # # Call the given domain to handle a value
154
- # # domain = self.domainIndex[value['domain']]
155
- # handler = domain.valueHandler(value['type'])
156
- # if handler: result = handler(value)
319
+ for part in value.getContent(): # pyright: ignore[reportOptionalMemberAccess]
320
+ val = self.evaluate(part) # pyright: ignore[reportAttributeAccessIssue]
321
+ if val != None:
322
+ if isinstance(val, ECValue): val = str(val.getContent())
323
+ if val == None: val = ''
324
+ else: content += str(val)
325
+ result.setValue(type=str, content=content)
326
+
157
327
  else:
158
328
  # Call the given domain to handle a value
159
- domain = self.domainIndex[value['domain']]
160
- handler = domain.valueHandler(value['type'])
329
+ domainName = value.getDomain() # type: ignore
330
+ if domainName == None: domainName = 'core'
331
+ domain = self.domainIndex[domainName]
332
+ handler = domain.valueHandler(value.getType()) # type: ignore
161
333
  if handler: result = handler(value)
162
334
 
163
335
  return result
164
336
 
165
- def constant(self, content, numeric):
166
- result = {}
167
- result['type'] = 'int' if numeric else 'text'
168
- result['content'] = content
169
- return result
170
-
171
- def evaluate(self, value):
172
- if value == None:
173
- result = {}
174
- result['type'] = 'text'
175
- result['content'] = ''
176
- return result
177
-
178
- result = self.doValue(value)
179
- if result:
180
- return result
181
- return None
182
-
183
- def getValue(self, value):
184
- return self.evaluate(value).content
185
-
186
- def getRuntimeValue(self, value):
337
+ # Get the runtime value of a value object (as a string or integer)
338
+ def textify(self, value):
339
+ self.ensureRunning()
187
340
  if value is None:
188
341
  return None
189
- v = self.evaluate(value)
190
- if v != None:
191
- content = v['content']
192
- if v['type'] == 'boolean':
193
- return True if content else False
194
- if v['type'] in ['int', 'float', 'text', 'object']:
195
- return content
196
- return ''
197
- return None
198
-
199
- def getSymbolContent(self, symbolRecord):
200
- if len(symbolRecord['value']) == 0:
201
- return None
202
- try: return symbolRecord['value'][symbolRecord['index']]
203
- except: RuntimeError(self, f'Cannot get content of symbol "{symbolRecord["name"]}"')
204
-
205
- def getSymbolValue(self, symbolRecord):
206
- if len(symbolRecord['value']) == 0:
342
+
343
+ if isinstance(value, dict):
344
+ value = value['object']
345
+ if isinstance(value, ECObject):
346
+ value = value.getValue()
347
+ if isinstance(value, ECValue): # type: ignore
348
+ v = self.evaluate(value) # type: ignore
349
+ else:
350
+ v = value
351
+ if v is None: return None
352
+ if isinstance(v, ECValue):
353
+ if v.getType() == 'object':
354
+ return value.getContent() # type: ignore
355
+ return v.getContent()
356
+ if isinstance(v, (dict, list)):
357
+ return json.dumps(v)
358
+ return v
359
+
360
+ # Get the content of a symbol
361
+ def getSymbolContent(self, record):
362
+ if len(record['value']) == 0:
207
363
  return None
208
- try: value = symbolRecord['value'][symbolRecord['index']]
209
- except: RuntimeError(self, f'Cannot get value of symbol "{symbolRecord["name"]}"')
210
- copy = deepcopy(value)
364
+ try: return record['value'][record['index']]
365
+ except: raise RuntimeError(self, f'Cannot get content of symbol "{record["name"]}"')
366
+
367
+ # Get the value of a symbol as an ECValue
368
+ def getSymbolValue(self, record):
369
+ self.ensureRunning()
370
+ object = self.getObject(record)
371
+ self.checkObjectType(object, ECObject)
372
+ value = object.getValue() # type: ignore
373
+ if value is None:
374
+ raise NoValueRuntimeError(self, f'Symbol "{record["name"]}" has no value')
375
+ # copy = deepcopy(value)
376
+ copy = ECValue(domain=value.getDomain(),type=value.getType(),content=deepcopy(value.getContent()))
211
377
  return copy
212
378
 
213
- def putSymbolValue(self, symbolRecord, value):
214
- if symbolRecord['locked']:
215
- name = symbolRecord['name']
216
- RuntimeError(self, f'Symbol "{name}" is locked')
217
- if symbolRecord['value'] == None or symbolRecord['value'] == []:
218
- symbolRecord['value'] = [value]
219
- else:
220
- index = symbolRecord['index']
221
- if index == None:
222
- index = 0
223
- symbolRecord['value'][index] = value
379
+ # Set the value of a symbol to either an ECValue or a raw value
380
+ def putSymbolValue(self, record, value):
381
+ variable = self.getObject(record)
382
+ if variable.isLocked(): # type: ignore
383
+ name = record['name']
384
+ raise RuntimeError(self, f'Symbol "{name}" is locked')
385
+ variable.setValue(self.getValueOf(value)) # type: ignore
224
386
 
225
387
  def encode(self, value):
226
388
  return value
@@ -287,9 +449,9 @@ class Program:
287
449
  return
288
450
 
289
451
  def releaseParent(self):
290
- if self.parent.waiting and self.parent.program.running:
291
- self.parent.waiting = False
292
- self.parent.program.run(self.parent.pc)
452
+ if self.parent and self.parent.waiting and self.parent.program.running: # type: ignore[union-attr]
453
+ self.parent.waiting = False # type: ignore[union-attr]
454
+ self.parent.program.run(self.parent.pc) # type: ignore[union-attr]
293
455
 
294
456
  # Flush the queue
295
457
  def flush(self, pc):
@@ -297,12 +459,21 @@ class Program:
297
459
  self.pc = pc
298
460
  while self.running:
299
461
  command = self.code[self.pc]
462
+
463
+ # Check if debugger wants to halt before executing this command
464
+ if self.debugger != None:
465
+ # pc==1 is the first real command (pc==0 is the debug loader)
466
+ is_first = (self.pc == 1)
467
+ if self.debugger.checkIfHalt(is_first):
468
+ # Debugger says halt - break out and wait for user
469
+ break
470
+
300
471
  domainName = command['domain']
301
472
  if domainName == None:
302
473
  self.pc += 1
303
474
  else:
304
475
  keyword = command['keyword']
305
- if self.debugStep and command['debug']:
476
+ if self.debugStep and not self.debugSkip and 'debug' in command:
306
477
  lino = command['lino'] + 1
307
478
  line = self.script.lines[command['lino']].strip()
308
479
  print(f'{self.name}: Line {lino}: {domainName}:{keyword}: {line}')
@@ -311,7 +482,12 @@ class Program:
311
482
  if handler:
312
483
  command = self.code[self.pc]
313
484
  command['program'] = self
314
- self.pc = handler(command)
485
+ try:
486
+ if self.breakpoint:
487
+ pass # Place a breakpoint here for a debugger to catch
488
+ self.pc = handler(command)
489
+ except Exception as e:
490
+ raise RuntimeError(self, f'Error during execution of {domainName}:{keyword}: {str(e)}')
315
491
  # Deal with 'exit'
316
492
  if self.pc == -1:
317
493
  queue = deque()
@@ -325,63 +501,48 @@ class Program:
325
501
  # Run the script at a given PC value
326
502
  def run(self, pc):
327
503
  global queue
328
- item = Object()
329
- item.program = self
330
- item.pc = pc
504
+ item = ECValue()
505
+ item.program = self # type: ignore
506
+ item.pc = pc # type: ignore
331
507
  queue.append(item)
508
+ self.running = True
332
509
 
333
510
  def kill(self):
334
511
  self.running = False
335
512
  if self.parent != None: self.parent.program.kill()
336
513
 
337
- def setExternalControl(self):
338
- self.externalControl = True
339
-
340
514
  def nonNumericValueError(self):
341
515
  FatalError(self.compiler, 'Non-numeric value')
342
516
 
343
- def variableDoesNotHoldAValueError(self, name):
344
- raise FatalError(self.compiler, f'Variable "{name}" does not hold a value')
345
-
346
- def noneValueError(self, name):
347
- raise FatalError(self.compiler, f'Value is None')
348
-
349
517
  def compare(self, value1, value2):
350
- val1 = self.evaluate(value1)
351
- val2 = self.evaluate(value2)
352
- if val1 == None or val2 == None:
518
+ if value1 == None or value2 == None:
519
+ RuntimeError(self, 'Cannot compare a value with None')
520
+ v1 = self.textify(value1)
521
+ v2 = self.textify(value2)
522
+ if v1 == None or v2 == None:
523
+ raise RuntimeError(self, 'Both items must have a value for comparison')
524
+ if type(v1) == str and type(v2) == str:
525
+ # String comparison
526
+ if v1 < v2: return -1
527
+ if v1 > v2: return 1
353
528
  return 0
354
- v1 = val1['content']
355
- v2 = val2['content']
356
- # if v1 == None and v2 != None or v1 != None and v2 == None:
357
- # return 0
358
- if v1 == None and v2 != None: return -1
359
- elif v2 == None and v1 != None: return 1
360
- if v1 != None and val1['type'] == 'int':
361
- if not val2['type'] == 'int':
362
- if type(v2) is str:
363
- try:
364
- v2 = int(v2)
365
- except:
366
- lino = self.code[self.pc]['lino'] + 1
367
- RuntimeError(None, f'Line {lino}: \'{v2}\' is not an integer')
368
- else:
369
- if v2 != None and val2['type'] == 'int':
370
- v2 = str(v2)
371
- if v1 == None:
372
- v1 = ''
373
- if v2 == None:
374
- v2 = ''
375
- if type(v1) == int:
376
- if type(v2) != int:
377
- v1 = f'{v1}'
378
- if type(v2) == int:
379
- if type(v1) != int:
380
- v2 = f'{v2}'
381
- if v1 > v2:
382
- return 1
383
- if v1 < v2:
529
+
530
+ if type(v1) is str:
531
+ try:
532
+ v1 = int(v1)
533
+ except:
534
+ print(f'{v1} is not an integer')
535
+ return None
536
+ if type(v2) is str:
537
+ try:
538
+ v2 = int(v2)
539
+ except:
540
+ print(f'{v2} is not an integer')
541
+ return None
542
+ if v1 < v2: # type: ignore[operator]
384
543
  return -1
544
+ if v1 > v2: # type: ignore[operator]
545
+ return 1
385
546
  return 0
386
547
 
387
548
  # Set up a message handler
@@ -396,7 +557,7 @@ class Program:
396
557
  # This is the program launcher
397
558
  def Main():
398
559
  if (len(sys.argv) > 1):
399
- Program(sys.argv[1]).start()
560
+ Program(' '.join(sys.argv[1:])).start()
400
561
  else:
401
562
  Program('-v')
402
563
 
easycoder/ec_psutil.py ADDED
@@ -0,0 +1,48 @@
1
+ from easycoder import Handler, ECValue
2
+ import os
3
+ from psutil import Process
4
+
5
+ class PSUtil(Handler):
6
+
7
+ def __init__(self, compiler):
8
+ Handler.__init__(self, compiler)
9
+
10
+ def getName(self):
11
+ return 'psutil'
12
+
13
+ #############################################################################
14
+ # Keyword handlers
15
+
16
+ #############################################################################
17
+ # Compile a value in this domain
18
+ def compileValue(self):
19
+ value = ECValue(domain=self.getName())
20
+ if self.tokenIs('the'):
21
+ self.nextToken()
22
+ token = self.getToken()
23
+ if token in ['mem', 'memory']:
24
+ value.setType('memory')
25
+ return value
26
+ return None
27
+
28
+ #############################################################################
29
+ # Modify a value or leave it unchanged.
30
+ def modifyValue(self, value):
31
+ return value
32
+
33
+ #############################################################################
34
+ # Value handlers
35
+
36
+ def v_memory(self, v):
37
+ process: Process = Process(os.getpid())
38
+ megabytes: float = process.memory_info().rss / (1024 * 1024)
39
+ return ECValue(domain=self.getName(), type=float, content=megabytes)
40
+
41
+ #############################################################################
42
+ # Compile a condition
43
+ def compileCondition(self):
44
+ condition = {}
45
+ return condition
46
+
47
+ #############################################################################
48
+ # Condition handlers
easycoder/ec_timestamp.py CHANGED
@@ -5,6 +5,7 @@ def getTimestamp(t):
5
5
  tz = pytz.timezone('GB') # Localize this!
6
6
  dt = datetime.fromtimestamp(t)
7
7
  # print(f'{dt} + {tz.dst(dt).seconds}')
8
- return int(t) + tz.dst(dt).seconds
8
+ dst = tz.dst(dt)
9
+ return int(t) + (dst.seconds if dst else 0)
9
10
 
10
11
  # Usage: print(getTimestamp(time.time()))