liveConsole 1.6.2__tar.gz → 1.7.0__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.

Potentially problematic release.


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

Files changed (24) hide show
  1. {liveconsole-1.6.2/src/liveConsole.egg-info → liveconsole-1.7.0}/PKG-INFO +21 -1
  2. {liveconsole-1.6.2 → liveconsole-1.7.0}/README.md +20 -0
  3. {liveconsole-1.6.2 → liveconsole-1.7.0}/pyproject.toml +1 -1
  4. {liveconsole-1.6.2 → liveconsole-1.7.0/src/liveConsole.egg-info}/PKG-INFO +21 -1
  5. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/mainConsole.py +41 -21
  6. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/pysole.py +54 -14
  7. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/settings.json +1 -0
  8. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/styledTextbox.py +1 -0
  9. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/themes.json +4 -0
  10. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/utils.py +6 -0
  11. {liveconsole-1.6.2 → liveconsole-1.7.0}/LICENSE +0 -0
  12. {liveconsole-1.6.2 → liveconsole-1.7.0}/MANIFEST.in +0 -0
  13. {liveconsole-1.6.2 → liveconsole-1.7.0}/setup.cfg +0 -0
  14. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/liveConsole.egg-info/SOURCES.txt +0 -0
  15. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/liveConsole.egg-info/dependency_links.txt +0 -0
  16. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/liveConsole.egg-info/entry_points.txt +0 -0
  17. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/liveConsole.egg-info/requires.txt +0 -0
  18. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/liveConsole.egg-info/top_level.txt +0 -0
  19. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/__init__.py +0 -0
  20. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/__main__.py +0 -0
  21. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/commandHistory.py +0 -0
  22. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/helpTab.py +0 -0
  23. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/liveConsole.py +0 -0
  24. {liveconsole-1.6.2 → liveconsole-1.7.0}/src/pysole/suggestionManager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liveConsole
3
- Version: 1.6.2
3
+ Version: 1.7.0
4
4
  Summary: An IDLE-like debugger to allow for real-time command injection for debugging and testing python code
5
5
  Author-email: Tzur Soffer <tzur.soffer@gmail.com>
6
6
  License: MIT
@@ -21,6 +21,8 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
21
21
  * Python syntax highlighting via **Pygments**
22
22
 
23
23
  * Autocomplete for **keywords, built-ins, and local/global variables**
24
+
25
+ * Run code at startup for easier debugging
24
26
 
25
27
  * Thread-safe execution of Python code
26
28
 
@@ -52,6 +54,15 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
52
54
 
53
55
  * Highlights Python keywords, built-ins, and expressions in the console.
54
56
 
57
+ ### Run Code at Startup
58
+
59
+ * Pysole can automatically execute Python code when the console launches.
60
+
61
+ * Use the runRemainingCode=True argument in pysole.probe() to run all remaining lines in the calling script after the probe() call.
62
+
63
+ * The printStartupCode flag controls whether these lines are printed in the console as they execute (True) or run silently (False).
64
+
65
+ * Useful for initializing variables, importing libraries, or setting up your environment automatically.
55
66
 
56
67
  ### Autocomplete
57
68
 
@@ -110,6 +121,15 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
110
121
  import pysole
111
122
  pysole.probe()
112
123
  ```
124
+ or for also running some code at the startup of the pysole
125
+ ```
126
+ import pysole
127
+ pysole.probe(runRemainingCode=True, #< for executing the code below probe
128
+ printStartupCode=True #< for printing the command as well as it output
129
+ )
130
+ x = 1 #< initialize some variable
131
+ print(x) #< print the variable on the console
132
+ ```
113
133
 
114
134
  * Type Python commands in the `>>>` prompt and see live output.
115
135
 
@@ -8,6 +8,8 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
8
8
  * Python syntax highlighting via **Pygments**
9
9
 
10
10
  * Autocomplete for **keywords, built-ins, and local/global variables**
11
+
12
+ * Run code at startup for easier debugging
11
13
 
12
14
  * Thread-safe execution of Python code
13
15
 
@@ -39,6 +41,15 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
39
41
 
40
42
  * Highlights Python keywords, built-ins, and expressions in the console.
41
43
 
44
+ ### Run Code at Startup
45
+
46
+ * Pysole can automatically execute Python code when the console launches.
47
+
48
+ * Use the runRemainingCode=True argument in pysole.probe() to run all remaining lines in the calling script after the probe() call.
49
+
50
+ * The printStartupCode flag controls whether these lines are printed in the console as they execute (True) or run silently (False).
51
+
52
+ * Useful for initializing variables, importing libraries, or setting up your environment automatically.
42
53
 
43
54
  ### Autocomplete
44
55
 
@@ -97,6 +108,15 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
97
108
  import pysole
98
109
  pysole.probe()
99
110
  ```
111
+ or for also running some code at the startup of the pysole
112
+ ```
113
+ import pysole
114
+ pysole.probe(runRemainingCode=True, #< for executing the code below probe
115
+ printStartupCode=True #< for printing the command as well as it output
116
+ )
117
+ x = 1 #< initialize some variable
118
+ print(x) #< print the variable on the console
119
+ ```
100
120
 
101
121
  * Type Python commands in the `>>>` prompt and see live output.
102
122
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "liveConsole"
3
- version = "1.6.2"
3
+ version = "1.7.0"
4
4
  description = "An IDLE-like debugger to allow for real-time command injection for debugging and testing python code"
5
5
  authors = [{ name="Tzur Soffer", email="tzur.soffer@gmail.com" }]
6
6
  license = {text = "MIT"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liveConsole
3
- Version: 1.6.2
3
+ Version: 1.7.0
4
4
  Summary: An IDLE-like debugger to allow for real-time command injection for debugging and testing python code
5
5
  Author-email: Tzur Soffer <tzur.soffer@gmail.com>
6
6
  License: MIT
@@ -21,6 +21,8 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
21
21
  * Python syntax highlighting via **Pygments**
22
22
 
23
23
  * Autocomplete for **keywords, built-ins, and local/global variables**
24
+
25
+ * Run code at startup for easier debugging
24
26
 
25
27
  * Thread-safe execution of Python code
26
28
 
@@ -52,6 +54,15 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
52
54
 
53
55
  * Highlights Python keywords, built-ins, and expressions in the console.
54
56
 
57
+ ### Run Code at Startup
58
+
59
+ * Pysole can automatically execute Python code when the console launches.
60
+
61
+ * Use the runRemainingCode=True argument in pysole.probe() to run all remaining lines in the calling script after the probe() call.
62
+
63
+ * The printStartupCode flag controls whether these lines are printed in the console as they execute (True) or run silently (False).
64
+
65
+ * Useful for initializing variables, importing libraries, or setting up your environment automatically.
55
66
 
56
67
  ### Autocomplete
57
68
 
@@ -110,6 +121,15 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
110
121
  import pysole
111
122
  pysole.probe()
112
123
  ```
124
+ or for also running some code at the startup of the pysole
125
+ ```
126
+ import pysole
127
+ pysole.probe(runRemainingCode=True, #< for executing the code below probe
128
+ printStartupCode=True #< for printing the command as well as it output
129
+ )
130
+ x = 1 #< initialize some variable
131
+ print(x) #< print the variable on the console
132
+ ```
113
133
 
114
134
  * Type Python commands in the `>>>` prompt and see live output.
115
135
 
@@ -3,6 +3,7 @@ import traceback
3
3
  from .suggestionManager import CodeSuggestionManager
4
4
  from .commandHistory import CommandHistory
5
5
  from .styledTextbox import StyledTextWindow
6
+ from .utils import stdPrint
6
7
 
7
8
  import tkinter as tk
8
9
 
@@ -11,16 +12,16 @@ class InteractiveConsoleText(StyledTextWindow):
11
12
  def __init__(self, master, helpTab, theme, font, behavior, userLocals=None, userGlobals=None, **kwargs):
12
13
  super().__init__(master, theme=theme, font=font, **kwargs)
13
14
  self.font=(font["FONT"], font["FONT_SIZE"])
14
-
15
+
15
16
  # Initialize components
16
17
  self.PROMPT = behavior["PRIMARY_PROMPT"]
17
18
  self.PROMPT_LENGTH = len(self.PROMPT)
18
19
  self.suggestionManager = CodeSuggestionManager(self, userLocals=userLocals, userGlobals=userGlobals, theme=theme, font=font)
19
20
  self.helpTab = helpTab
20
-
21
+
21
22
  self.navigatingHistory = False
22
23
  self.history = CommandHistory()
23
-
24
+
24
25
  self.inputVar = tk.StringVar()
25
26
  self.waitingForInput = False
26
27
  self.inputLine = "1.0"
@@ -28,10 +29,10 @@ class InteractiveConsoleText(StyledTextWindow):
28
29
  # Track current command
29
30
  self.currentCommandLine = 1
30
31
  self.isExecuting = False
31
-
32
+
32
33
  # Setup bindings
33
34
  self._setupBindings()
34
-
35
+
35
36
  # Initialize with first prompt
36
37
  self.addPrompt()
37
38
 
@@ -52,11 +53,14 @@ class InteractiveConsoleText(StyledTextWindow):
52
53
  def getCurrentLineNumber(self):
53
54
  """Get the line number where current command starts."""
54
55
  return(int(self.index("end-1c").split(".")[0]))
55
-
56
+
57
+ def resetCurrentLineNumber(self):
58
+ self.currentCommandLine = self.getCurrentLineNumber()
59
+
56
60
  def getCommandStartPosition(self):
57
61
  """Get the starting position of the current command."""
58
62
  return(f"{self.currentCommandLine}.0")
59
-
63
+
60
64
  def replaceCurrentCommand(self, newCommand):
61
65
  """Replace the current command with new text."""
62
66
  if self.isExecuting:
@@ -73,6 +77,16 @@ class InteractiveConsoleText(StyledTextWindow):
73
77
  # Ensure styling/lexer applied after programmatic change:
74
78
  self.updateStyling(start=self.getPromptPosition())
75
79
 
80
+ def runCommand(self, command, printCommand=False):
81
+ """Insert code into the console prompt and execute it as if Enter was pressed."""
82
+ if self.isExecuting:
83
+ return(False)
84
+ if printCommand:
85
+ self.replaceCurrentCommand(command) #< Replace current command with the new code
86
+ self.onEnter(None) #< Simulate pressing Enter to run the command
87
+ else:
88
+ self.executeCommandThreaded(command, addPrompt=False)
89
+
76
90
  def isCursorInEditableArea(self):
77
91
  """Check if cursor is in the editable command area."""
78
92
  if self.isExecuting:
@@ -94,25 +108,26 @@ class InteractiveConsoleText(StyledTextWindow):
94
108
  self.inputVar.set(line)
95
109
  self.waitingForInput = False
96
110
  return("break")
97
-
111
+
98
112
  if self.isExecuting:
99
113
  return("break")
100
-
114
+
101
115
  command = self.getCurrentCommand()
102
-
116
+ # print(command)
117
+
103
118
  if not command.strip():
104
119
  return("break")
105
-
120
+
106
121
  # Check if statement is incomplete
107
122
  if self.isIncompleteStatement(command):
108
123
  return(self.onShiftEnter(event))
109
-
124
+
110
125
  # Execute the command
111
126
  self.history.add(command)
112
127
  self.mark_set("insert", "end")
113
128
  self.insert("end", "\n")
114
129
  self.see("end")
115
-
130
+
116
131
  # Execute in thread
117
132
  self.isExecuting = True
118
133
  threading.Thread(
@@ -120,7 +135,7 @@ class InteractiveConsoleText(StyledTextWindow):
120
135
  args=(command,),
121
136
  daemon=True
122
137
  ).start()
123
-
138
+
124
139
  return("break")
125
140
 
126
141
  def readInput(self):
@@ -324,13 +339,17 @@ class InteractiveConsoleText(StyledTextWindow):
324
339
 
325
340
  return(currentIndent)
326
341
 
327
- def writeOutput(self, text, tag="output"):
342
+ def writeOutput(self, text, tag="output", loc="end"):
328
343
  """Write output to the console (thread-safe)."""
329
344
  def _write():
330
- self.insert("end", text + "\n", tag)
345
+ self.insert(loc, text + "\n", tag)
331
346
  self.see("end")
332
347
 
333
348
  self.after(0, _write)
349
+
350
+ def newline(self):
351
+ """Insert a newline at the end."""
352
+ self.writeOutput("")
334
353
 
335
354
  def getPromptPosition(self):
336
355
  """Get the position right after the prompt on current command line."""
@@ -357,16 +376,15 @@ class InteractiveConsoleText(StyledTextWindow):
357
376
  self.mark_set("insert", "end")
358
377
  self.see("end")
359
378
  self.isExecuting = False
360
-
379
+
361
380
  if self.isExecuting:
362
381
  self.after(0, _add)
363
382
  else:
364
383
  _add()
365
384
 
366
- def executeCommandThreaded(self, command):
385
+ def executeCommandThreaded(self, command, addPrompt=True):
367
386
  """Execute a command in a separate thread."""
368
387
  try:
369
- # Try eval first for expressions
370
388
  result = eval(command, self.master.userGlobals, self.master.userLocals)
371
389
  if result is not None:
372
390
  self.writeOutput(str(result), "result")
@@ -380,5 +398,7 @@ class InteractiveConsoleText(StyledTextWindow):
380
398
  except Exception:
381
399
  self.writeOutput(traceback.format_exc(), "error")
382
400
 
383
- # Add new prompt after execution
384
- self.addPrompt()
401
+ if addPrompt:
402
+ self.addPrompt()
403
+ else:
404
+ self.isExecuting = False
@@ -1,3 +1,5 @@
1
+ import threading
2
+ import time
1
3
  import customtkinter as ctk
2
4
  import tkinter as tk
3
5
  from tkinter import messagebox
@@ -6,7 +8,7 @@ import sys
6
8
  import io
7
9
  import json
8
10
 
9
- from .utils import settingsPath, themesPath
11
+ from .utils import settingsPath, themesPath, stdPrint
10
12
  from .helpTab import HelpTab
11
13
  from .mainConsole import InteractiveConsoleText
12
14
 
@@ -35,15 +37,17 @@ class StdinRedirect(io.StringIO):
35
37
 
36
38
  class InteractiveConsole(ctk.CTk):
37
39
  """Main console window application."""
38
-
39
- def __init__(self, userGlobals=None, userLocals=None, callerFrame=None, theme=None, defaultSize=None, primaryPrompt=None):
40
+
41
+ def __init__(self, userGlobals=None, userLocals=None, callerFrame=None,
42
+ defaultSize=None, primaryPrompt=None,
43
+ runRemainingCode=False, printStartupCode=True):
40
44
  super().__init__()
41
45
  with open(settingsPath, "r") as f:
42
46
  settings = json.load(f)
43
47
  self.THEME = settings["THEME"]
44
48
  self.FONT = self.THEME["FONT"]
45
49
  self.BEHAVIOR = settings["BEHAVIOR"]
46
-
50
+
47
51
  if primaryPrompt != None:
48
52
  self.BEHAVIOR["PRIMARY_PROMPT"] = primaryPrompt
49
53
  if defaultSize != None:
@@ -51,7 +55,7 @@ class InteractiveConsole(ctk.CTk):
51
55
 
52
56
  self.title("Live Interactive Console")
53
57
  self.geometry(self.BEHAVIOR["DEFAULT_SIZE"])
54
-
58
+
55
59
  ctk.set_appearance_mode(self.THEME["APPEARANCE"])
56
60
  ctk.set_default_color_theme("blue")
57
61
 
@@ -63,17 +67,30 @@ class InteractiveConsole(ctk.CTk):
63
67
  userGlobals = callerFrame.f_globals
64
68
  if userLocals is None:
65
69
  userLocals = callerFrame.f_locals
66
-
70
+
67
71
  self.userGlobals = userGlobals
68
72
  self.userLocals = userLocals
69
-
73
+
70
74
  # Create UI
71
75
  self._createMenu()
72
76
  self._createUi()
73
-
77
+
74
78
  # Redirect stdout/stderr
75
79
  self._setupOutputRedirect()
76
80
  self._setupInputRedirect()
81
+
82
+ self.printStartupCode = printStartupCode
83
+ self.startupCode = ()
84
+ if runRemainingCode:
85
+ code_obj = callerFrame.f_code
86
+ filename = code_obj.co_filename
87
+
88
+ # Read the rest of the file after the call to probe()
89
+ with open(filename, "r", encoding="utf-8") as f:
90
+ lines = f.readlines()
91
+
92
+ startLine = callerFrame.f_lineno
93
+ self.startupCode = lines[startLine:]
77
94
 
78
95
  def _createMenu(self):
79
96
  """Create a menu bar using CTkOptionMenu."""
@@ -99,7 +116,7 @@ class InteractiveConsole(ctk.CTk):
99
116
  self._editSettings()
100
117
  elif choice == "Load Theme":
101
118
  self._loadTheme()
102
-
119
+
103
120
  def _loadTheme(self):
104
121
  """
105
122
  Open a CTk popup to let the user choose a theme from themes.json.
@@ -218,28 +235,51 @@ class InteractiveConsole(ctk.CTk):
218
235
  self.console.pack(fill="both", expand=True, padx=5, pady=5)
219
236
  self.console.master = self
220
237
 
221
-
222
238
  def _setupOutputRedirect(self):
223
239
  """Setup stdout/stderr redirection to console."""
224
240
  sys.stdout = StdoutRedirect(self.console.writeOutput)
225
241
  sys.stderr = StdoutRedirect(
226
- lambda text, tag: self.console.writeOutput(text, "error")
242
+ lambda text, tag: self.console.writeOutput(text, "error", "end")
227
243
  )
228
244
 
229
245
  def _setupInputRedirect(self):
230
246
  """Setup stdin redirection to console."""
231
247
  sys.stdin = StdinRedirect(self.console.readInput)
232
-
248
+
249
+ def onClose(self):
250
+ sys.stdout = sys.__stdout__
251
+ sys.stderr = sys.__stderr__
252
+ self.destroy()
253
+
233
254
  def probe(self, *args, **kwargs):
234
255
  """Start the console main loop."""
256
+ def runStartup():
257
+ self.console.newline()
258
+ self.console.writeOutput("Welcome to Pysole, if you find me useful, please star me on github:\nhttps://github.com/TzurSoffer/Pysole", "instruction")
259
+ for line in self.startupCode:
260
+ line = line.rstrip()
261
+ while self.console.isExecuting:
262
+ time.sleep(0.01)
263
+ if self.printStartupCode:
264
+ self.console.runCommand(line, printCommand=True)
265
+ else:
266
+ self.console.runCommand(line, printCommand=False)
267
+
268
+ if self.printStartupCode == False:
269
+ self.console.resetCurrentLineNumber()
270
+ self.console.addPrompt()
271
+ threading.Thread(target=runStartup).start()
235
272
  self.mainloop(*args, **kwargs)
236
273
 
237
- def probe(userGlobals=None, userLocals=None, callerFrame=None):
274
+ def probe(userGlobals=None, userLocals=None, callerFrame=None, runRemainingCode=False, printStartupCode=False, **kwargs):
238
275
  if callerFrame == None:
239
276
  callerFrame = inspect.currentframe().f_back
240
277
  InteractiveConsole(userGlobals=userGlobals,
241
278
  userLocals=userLocals,
242
- callerFrame=callerFrame).probe()
279
+ callerFrame=callerFrame,
280
+ runRemainingCode=runRemainingCode,
281
+ printStartupCode=printStartupCode,
282
+ **kwargs).probe()
243
283
 
244
284
  def _standalone():
245
285
  import pysole
@@ -11,6 +11,7 @@
11
11
  "OUTPUT": "#ffffff",
12
12
  "ERROR": "#ff0000",
13
13
  "RESULT": "#66ccff",
14
+ "INSTRUCTION": "#ffff00",
14
15
  "SUGGESTION_BOX_BG": "#2d2d2d",
15
16
  "SUGGESTION_BOX_SELECTION_BG": "#0066cc",
16
17
  "FONT": {
@@ -19,6 +19,7 @@ class StyledTextWindow(tk.Text):
19
19
  self.tag_configure("output", foreground=theme["OUTPUT"], font=(font["FONT"], font["FONT_SIZE"]))
20
20
  self.tag_configure("error", foreground=theme["ERROR"], font=(font["FONT"], font["FONT_SIZE"]))
21
21
  self.tag_configure("result", foreground=theme["RESULT"], font=(font["FONT"], font["FONT_SIZE"]))
22
+ self.tag_configure("instruction", foreground=theme["INSTRUCTION"], font=(font["FONT"], font["FONT_SIZE"]))
22
23
 
23
24
  # Configure syntax highlighting tags
24
25
  for token, style in self.style:
@@ -11,6 +11,7 @@
11
11
  "OUTPUT": "#ffffff",
12
12
  "ERROR": "#ff0000",
13
13
  "RESULT": "#66ccff",
14
+ "INSTRUCTION": "#ffff00",
14
15
  "SUGGESTION_BOX_BG": "#2d2d2d",
15
16
  "SUGGESTION_BOX_SELECTION_BG": "#0066cc",
16
17
  "FONT": {
@@ -30,6 +31,7 @@
30
31
  "OUTPUT": "#000000",
31
32
  "ERROR": "#ff0000",
32
33
  "RESULT": "#0066cc",
34
+ "INSTRUCTION": "#ffff00",
33
35
  "SUGGESTION_BOX_BG": "#f0f0f0",
34
36
  "SUGGESTION_BOX_SELECTION_BG": "#cce6ff",
35
37
  "FONT": {
@@ -49,6 +51,7 @@
49
51
  "OUTPUT": "#586e75",
50
52
  "ERROR": "#dc322f",
51
53
  "RESULT": "#2aa198",
54
+ "INSTRUCTION": "#ffff00",
52
55
  "SUGGESTION_BOX_BG": "#eee8d5",
53
56
  "SUGGESTION_BOX_SELECTION_BG": "#b58900",
54
57
  "FONT": {
@@ -68,6 +71,7 @@
68
71
  "OUTPUT": "#f8f8f2",
69
72
  "ERROR": "#ff5555",
70
73
  "RESULT": "#8be9fd",
74
+ "INSTRUCTION": "#ffff00",
71
75
  "SUGGESTION_BOX_BG": "#44475a",
72
76
  "SUGGESTION_BOX_SELECTION_BG": "#6272a4",
73
77
  "FONT": {
@@ -1,4 +1,10 @@
1
1
  import os
2
+ import sys
2
3
 
3
4
  settingsPath = os.path.join(os.path.dirname(__file__), "settings.json")
4
5
  themesPath = os.path.join(os.path.dirname(__file__), "themes.json")
6
+
7
+ def stdPrint(text):
8
+ """Print text to the terminal."""
9
+ sys.__stdout__.write(f"{text}\n")
10
+ sys.__stdout__.flush()
File without changes
File without changes
File without changes