pygpt-net 2.6.21__py3-none-any.whl → 2.6.23__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.
Files changed (160) hide show
  1. pygpt_net/CHANGELOG.txt +12 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +3 -1
  4. pygpt_net/controller/__init__.py +4 -8
  5. pygpt_net/controller/access/voice.py +2 -2
  6. pygpt_net/controller/agent/llama.py +3 -0
  7. pygpt_net/controller/assistant/batch.py +2 -3
  8. pygpt_net/controller/assistant/editor.py +2 -2
  9. pygpt_net/controller/assistant/files.py +2 -3
  10. pygpt_net/controller/assistant/store.py +2 -2
  11. pygpt_net/controller/audio/audio.py +2 -2
  12. pygpt_net/controller/chat/response.py +4 -0
  13. pygpt_net/controller/ctx/ctx.py +2 -1
  14. pygpt_net/controller/files/files.py +24 -55
  15. pygpt_net/controller/idx/indexer.py +85 -76
  16. pygpt_net/controller/lang/lang.py +52 -34
  17. pygpt_net/controller/model/importer.py +2 -2
  18. pygpt_net/controller/notepad/notepad.py +86 -84
  19. pygpt_net/controller/plugins/settings.py +3 -4
  20. pygpt_net/controller/settings/profile.py +105 -124
  21. pygpt_net/controller/theme/menu.py +154 -57
  22. pygpt_net/controller/theme/nodes.py +51 -44
  23. pygpt_net/controller/theme/theme.py +33 -9
  24. pygpt_net/controller/tools/tools.py +2 -2
  25. pygpt_net/controller/ui/tabs.py +2 -3
  26. pygpt_net/core/agents/observer/evaluation.py +2 -2
  27. pygpt_net/core/agents/runners/loop.py +1 -0
  28. pygpt_net/core/bridge/bridge.py +2 -0
  29. pygpt_net/core/ctx/container.py +13 -12
  30. pygpt_net/core/ctx/output.py +7 -4
  31. pygpt_net/core/debug/console/console.py +2 -2
  32. pygpt_net/core/filesystem/actions.py +1 -2
  33. pygpt_net/core/filesystem/opener.py +261 -0
  34. pygpt_net/core/filesystem/url.py +13 -10
  35. pygpt_net/core/platforms/platforms.py +5 -4
  36. pygpt_net/core/render/plain/helpers.py +2 -5
  37. pygpt_net/core/render/plain/renderer.py +26 -30
  38. pygpt_net/core/render/web/body.py +1 -1
  39. pygpt_net/core/settings/settings.py +43 -13
  40. pygpt_net/core/tabs/tabs.py +20 -13
  41. pygpt_net/data/config/config.json +4 -4
  42. pygpt_net/data/config/models.json +3 -3
  43. pygpt_net/data/css/web-blocks.dark.css +7 -1
  44. pygpt_net/data/css/web-blocks.light.css +5 -2
  45. pygpt_net/data/css/web-chatgpt.dark.css +7 -1
  46. pygpt_net/data/css/web-chatgpt.light.css +3 -0
  47. pygpt_net/data/css/web-chatgpt_wide.dark.css +7 -1
  48. pygpt_net/data/css/web-chatgpt_wide.light.css +3 -0
  49. pygpt_net/data/locale/locale.de.ini +5 -1
  50. pygpt_net/data/locale/locale.en.ini +5 -1
  51. pygpt_net/data/locale/locale.es.ini +5 -1
  52. pygpt_net/data/locale/locale.fr.ini +5 -1
  53. pygpt_net/data/locale/locale.it.ini +5 -1
  54. pygpt_net/data/locale/locale.pl.ini +6 -4
  55. pygpt_net/data/locale/locale.uk.ini +5 -1
  56. pygpt_net/data/locale/locale.zh.ini +5 -1
  57. pygpt_net/plugin/twitter/plugin.py +2 -2
  58. pygpt_net/provider/core/config/patch.py +12 -1
  59. pygpt_net/tools/audio_transcriber/ui/dialogs.py +44 -54
  60. pygpt_net/tools/code_interpreter/body.py +1 -2
  61. pygpt_net/tools/code_interpreter/tool.py +7 -4
  62. pygpt_net/tools/code_interpreter/ui/html.py +1 -3
  63. pygpt_net/tools/code_interpreter/ui/widgets.py +2 -3
  64. pygpt_net/tools/html_canvas/ui/widgets.py +1 -3
  65. pygpt_net/tools/image_viewer/ui/dialogs.py +40 -37
  66. pygpt_net/tools/indexer/ui/widgets.py +2 -4
  67. pygpt_net/tools/media_player/tool.py +2 -5
  68. pygpt_net/tools/media_player/ui/widgets.py +60 -36
  69. pygpt_net/tools/text_editor/ui/widgets.py +18 -19
  70. pygpt_net/tools/translator/ui/widgets.py +39 -35
  71. pygpt_net/ui/base/context_menu.py +9 -4
  72. pygpt_net/ui/dialog/db.py +1 -3
  73. pygpt_net/ui/dialog/models.py +1 -3
  74. pygpt_net/ui/dialog/models_importer.py +2 -4
  75. pygpt_net/ui/dialogs.py +34 -30
  76. pygpt_net/ui/layout/chat/attachments.py +72 -84
  77. pygpt_net/ui/layout/chat/attachments_ctx.py +40 -44
  78. pygpt_net/ui/layout/chat/attachments_uploaded.py +36 -39
  79. pygpt_net/ui/layout/chat/calendar.py +100 -70
  80. pygpt_net/ui/layout/chat/chat.py +23 -17
  81. pygpt_net/ui/layout/chat/input.py +95 -118
  82. pygpt_net/ui/layout/chat/output.py +100 -162
  83. pygpt_net/ui/layout/chat/painter.py +89 -61
  84. pygpt_net/ui/layout/ctx/ctx_list.py +43 -52
  85. pygpt_net/ui/layout/status.py +23 -14
  86. pygpt_net/ui/layout/toolbox/agent.py +27 -38
  87. pygpt_net/ui/layout/toolbox/agent_llama.py +41 -45
  88. pygpt_net/ui/layout/toolbox/assistants.py +42 -38
  89. pygpt_net/ui/layout/toolbox/computer_env.py +32 -23
  90. pygpt_net/ui/layout/toolbox/footer.py +13 -16
  91. pygpt_net/ui/layout/toolbox/image.py +18 -21
  92. pygpt_net/ui/layout/toolbox/indexes.py +46 -89
  93. pygpt_net/ui/layout/toolbox/mode.py +20 -7
  94. pygpt_net/ui/layout/toolbox/model.py +12 -10
  95. pygpt_net/ui/layout/toolbox/presets.py +68 -52
  96. pygpt_net/ui/layout/toolbox/prompt.py +31 -58
  97. pygpt_net/ui/layout/toolbox/toolbox.py +25 -21
  98. pygpt_net/ui/layout/toolbox/vision.py +20 -22
  99. pygpt_net/ui/main.py +2 -4
  100. pygpt_net/ui/menu/about.py +64 -84
  101. pygpt_net/ui/menu/audio.py +87 -63
  102. pygpt_net/ui/menu/config.py +121 -127
  103. pygpt_net/ui/menu/debug.py +69 -76
  104. pygpt_net/ui/menu/file.py +32 -35
  105. pygpt_net/ui/menu/menu.py +2 -3
  106. pygpt_net/ui/menu/plugins.py +69 -33
  107. pygpt_net/ui/menu/theme.py +45 -46
  108. pygpt_net/ui/menu/tools.py +56 -60
  109. pygpt_net/ui/menu/video.py +20 -25
  110. pygpt_net/ui/tray.py +1 -2
  111. pygpt_net/ui/widget/audio/bar.py +1 -3
  112. pygpt_net/ui/widget/audio/input_button.py +3 -4
  113. pygpt_net/ui/widget/calendar/select.py +1 -2
  114. pygpt_net/ui/widget/dialog/base.py +12 -9
  115. pygpt_net/ui/widget/dialog/editor_file.py +20 -23
  116. pygpt_net/ui/widget/dialog/find.py +25 -24
  117. pygpt_net/ui/widget/dialog/profile.py +57 -53
  118. pygpt_net/ui/widget/draw/painter.py +62 -93
  119. pygpt_net/ui/widget/element/button.py +42 -30
  120. pygpt_net/ui/widget/element/checkbox.py +23 -15
  121. pygpt_net/ui/widget/element/group.py +6 -5
  122. pygpt_net/ui/widget/element/labels.py +1 -2
  123. pygpt_net/ui/widget/filesystem/explorer.py +93 -102
  124. pygpt_net/ui/widget/image/display.py +1 -2
  125. pygpt_net/ui/widget/lists/assistant.py +1 -2
  126. pygpt_net/ui/widget/lists/attachment.py +1 -2
  127. pygpt_net/ui/widget/lists/attachment_ctx.py +1 -2
  128. pygpt_net/ui/widget/lists/context.py +2 -4
  129. pygpt_net/ui/widget/lists/index.py +1 -2
  130. pygpt_net/ui/widget/lists/model.py +1 -2
  131. pygpt_net/ui/widget/lists/model_editor.py +1 -2
  132. pygpt_net/ui/widget/lists/model_importer.py +1 -2
  133. pygpt_net/ui/widget/lists/preset.py +1 -2
  134. pygpt_net/ui/widget/lists/preset_plugins.py +1 -2
  135. pygpt_net/ui/widget/lists/profile.py +1 -2
  136. pygpt_net/ui/widget/lists/uploaded.py +1 -2
  137. pygpt_net/ui/widget/option/checkbox.py +2 -4
  138. pygpt_net/ui/widget/option/checkbox_list.py +1 -4
  139. pygpt_net/ui/widget/option/cmd.py +1 -4
  140. pygpt_net/ui/widget/option/dictionary.py +25 -28
  141. pygpt_net/ui/widget/option/input.py +1 -3
  142. pygpt_net/ui/widget/tabs/Input.py +16 -12
  143. pygpt_net/ui/widget/tabs/body.py +5 -3
  144. pygpt_net/ui/widget/tabs/layout.py +41 -28
  145. pygpt_net/ui/widget/tabs/output.py +442 -85
  146. pygpt_net/ui/widget/textarea/calendar_note.py +1 -2
  147. pygpt_net/ui/widget/textarea/editor.py +41 -73
  148. pygpt_net/ui/widget/textarea/find.py +11 -10
  149. pygpt_net/ui/widget/textarea/html.py +3 -6
  150. pygpt_net/ui/widget/textarea/input.py +134 -69
  151. pygpt_net/ui/widget/textarea/notepad.py +54 -38
  152. pygpt_net/ui/widget/textarea/output.py +65 -54
  153. pygpt_net/ui/widget/textarea/search_input.py +5 -4
  154. pygpt_net/ui/widget/textarea/web.py +2 -4
  155. pygpt_net/ui/widget/vision/camera.py +2 -31
  156. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/METADATA +38 -174
  157. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/RECORD +160 -159
  158. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/LICENSE +0 -0
  159. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/WHEEL +0 -0
  160. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,15 @@
1
+ 2.6.23 (2025-08-25)
2
+
3
+ - Added an inline "Add a new chat" button to the right of the tabs.
4
+ - Added an "Add Attachment" button in the input field.
5
+ - Improved file open in the system's file manager
6
+ - Fixed the restoration of input text color when changing themes from light to dark.
7
+ - Fixed last eval step finish if 100% complete.
8
+
9
+ 2.6.22 (2025-08-25)
10
+
11
+ - UI refactor and optimizations.
12
+
1
13
  2.6.21 (2025-08-24)
2
14
 
3
15
  - Ollama models are now available in OpenAI Agents mode.
pygpt_net/__init__.py CHANGED
@@ -6,15 +6,15 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.24 00:00:00 #
9
+ # Updated Date: 2025.08.25 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  __author__ = "Marcin Szczygliński"
13
13
  __copyright__ = "Copyright 2025, Marcin Szczygliński"
14
14
  __credits__ = ["Marcin Szczygliński"]
15
15
  __license__ = "MIT"
16
- __version__ = "2.6.21"
17
- __build__ = "2025-08-24"
16
+ __version__ = "2.6.23"
17
+ __build__ = "2025-08-25"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
20
20
  __report__ = "https://github.com/szczyglis-dev/py-gpt/issues"
pygpt_net/app.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.22 10:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -14,6 +14,8 @@ import builtins
14
14
  import io
15
15
  import platform
16
16
 
17
+ import pygpt_net.icons_rc
18
+
17
19
  # disable warnings
18
20
  os.environ["TRANSFORMERS_NO_ADVISORY_WARNINGS"] = "1"
19
21
  os.environ["QT_LOGGING_RULES"] = "qt.multimedia.ffmpeg=false;qt.qpa.fonts=false"
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.20 23:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.controller.access import Access
@@ -39,7 +39,7 @@ from pygpt_net.controller.settings import Settings
39
39
  from pygpt_net.controller.theme import Theme
40
40
  from pygpt_net.controller.tools import Tools
41
41
  from pygpt_net.controller.ui import UI
42
- from pygpt_net.utils import mem_clean
42
+ from pygpt_net.utils import trans
43
43
 
44
44
 
45
45
  class Controller:
@@ -109,8 +109,6 @@ class Controller:
109
109
  self.camera.setup_ui()
110
110
  self.access.setup()
111
111
 
112
-
113
-
114
112
  def post_setup(self):
115
113
  """Post-setup, after plugins are loaded"""
116
114
  self.settings.setup()
@@ -147,9 +145,7 @@ class Controller:
147
145
  """Reload components"""
148
146
  self.reloading = True # lock
149
147
 
150
- print("Reloading components... please wait...")
151
-
152
- mem_clean() # try to clean memory
148
+ print(trans("status.reloading.profile.begin"))
153
149
 
154
150
  prev_theme = self.window.core.config.get("theme")
155
151
 
@@ -183,4 +179,4 @@ class Controller:
183
179
 
184
180
  self.reloading = False # unlock
185
181
 
186
- print("[OK] Components reloaded successfully.")
182
+ print(trans("status.reloading.profile.end"))
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.07 22:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List, Dict, Any
@@ -14,7 +14,7 @@ from typing import Optional, List, Dict, Any
14
14
  import os
15
15
 
16
16
  from PySide6.QtCore import QTimer, Slot, QObject
17
- from qasync import QApplication
17
+ from PySide6.QtWidgets import QApplication
18
18
 
19
19
  from pygpt_net.item.ctx import CtxItem
20
20
  from pygpt_net.plugin.audio_input.worker import ControlWorker
@@ -104,6 +104,9 @@ class Llama:
104
104
 
105
105
  def on_end(self):
106
106
  """End of run"""
107
+ self.window.dispatch(KernelEvent(KernelEvent.STATE_IDLE, {
108
+ "id": "agent",
109
+ }))
107
110
  self.eval_step = 0 # reset evaluation step
108
111
  if self.window.core.config.get("agent.goal.notify"):
109
112
  # show notification if enabled and mode is not llama_index
@@ -6,13 +6,12 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, Any
13
13
 
14
- from qasync import QApplication
15
- from PySide6.QtWidgets import QFileDialog
14
+ from PySide6.QtWidgets import QFileDialog, QApplication
16
15
 
17
16
  from pygpt_net.utils import trans
18
17
 
@@ -6,13 +6,13 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
13
13
  from typing import Optional
14
14
 
15
- from qasync import QApplication
15
+ from PySide6.QtWidgets import QApplication
16
16
 
17
17
  from pygpt_net.core.types import MODEL_DEFAULT
18
18
  from pygpt_net.item.assistant import AssistantItem
@@ -6,17 +6,16 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  from typing import Optional, Dict, List
14
14
 
15
- from qasync import QApplication
15
+ from PySide6.QtWidgets import QApplication
16
16
 
17
17
  from pygpt_net.item.assistant import AssistantItem
18
18
  from pygpt_net.item.attachment import AttachmentItem
19
- from pygpt_net.item.ctx import CtxItem
20
19
  from pygpt_net.utils import trans
21
20
 
22
21
 
@@ -6,14 +6,14 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
13
13
  import json
14
14
  from typing import Optional
15
15
 
16
- from qasync import QApplication
16
+ from PySide6.QtWidgets import QApplication
17
17
 
18
18
  from pygpt_net.item.assistant import AssistantStoreItem
19
19
  from pygpt_net.utils import trans
@@ -6,13 +6,13 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.07 22:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  from typing import Optional
14
14
 
15
- from qasync import QApplication
15
+ from PySide6.QtWidgets import QApplication
16
16
 
17
17
  from pygpt_net.core.tabs.tab import Tab
18
18
  from pygpt_net.core.events import Event, BaseEvent
@@ -269,6 +269,10 @@ class Response:
269
269
  self.window.update_status(trans("status.agent.reasoning"))
270
270
  controller.chat.common.lock_input() # lock input, re-enable stop button
271
271
 
272
+ if ctx.extra is not None and (isinstance(ctx.extra, dict) and "agent_eval_finish" in ctx.extra):
273
+ controller.agent.llama.on_end(ctx)
274
+ return
275
+
272
276
  # agent final response
273
277
  if ctx.extra is not None and (isinstance(ctx.extra, dict) and "agent_finish" in ctx.extra):
274
278
  controller.agent.llama.on_finish(ctx) # evaluate response and continue if needed
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.23 15:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List
@@ -358,6 +358,7 @@ class Ctx:
358
358
 
359
359
  self.window.dispatch(AppEvent(AppEvent.CTX_CREATED))
360
360
  self.select(meta.id)
361
+ QTimer.singleShot(1000, self.window.controller.chat.common.focus_input)
361
362
  return meta
362
363
 
363
364
  def add(self, ctx: CtxItem):
@@ -6,21 +6,18 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.23 15:00:00 #
9
+ # Updated Date: 2025.08.25 18:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
13
13
  import os
14
14
  import shutil
15
15
  from typing import Optional
16
+ from shutil import copy2
16
17
 
17
- from PySide6.QtCore import QUrl
18
- from PySide6.QtGui import QDesktopServices
19
18
  from PySide6.QtWidgets import QFileDialog, QApplication
20
- from showinfm import show_in_file_manager
21
- from shutil import copy2
22
- import subprocess
23
19
 
20
+ from pygpt_net.core.filesystem.opener import Opener
24
21
  from pygpt_net.utils import trans
25
22
 
26
23
 
@@ -60,12 +57,12 @@ class Files:
60
57
  try:
61
58
  shutil.rmtree(path) # delete directory with all files
62
59
  self.window.update_status(
63
- "[OK] Deleted directory: {}".format(os.path.basename(path))
60
+ f"[OK] Deleted directory: {os.path.basename(path)}"
64
61
  )
65
62
  self.update_explorer()
66
63
  except Exception as e:
67
64
  self.window.core.debug.log(e)
68
- print("Error deleting directory: {} - {}".format(path, e))
65
+ print(f"Error deleting directory: {path} - {e}")
69
66
 
70
67
  def touch_file(
71
68
  self,
@@ -93,12 +90,12 @@ class Files:
93
90
  filepath = os.path.join(path, name)
94
91
  open(filepath, 'a').close()
95
92
  self.window.update_status(
96
- "[OK] Created file: {}".format(os.path.basename(filepath))
93
+ f"[OK] Created file: {filepath}"
97
94
  )
98
95
  self.update_explorer()
99
96
  except Exception as e:
100
97
  self.window.core.debug.log(e)
101
- print("Error creating file: {} - {}".format(path, e))
98
+ print(f"Error creating file: {path} - {e}")
102
99
 
103
100
  def delete(
104
101
  self,
@@ -130,12 +127,12 @@ class Files:
130
127
  try:
131
128
  os.remove(path)
132
129
  self.window.update_status(
133
- "[OK] Deleted file: {}".format(os.path.basename(path))
130
+ f"[OK] Deleted file: {os.path.basename(path)}"
134
131
  )
135
132
  self.update_explorer()
136
133
  except Exception as e:
137
134
  self.window.core.debug.log(e)
138
- print("Error deleting file: {} - {}".format(path, e))
135
+ print(f"Error deleting file: {path} - {e}")
139
136
 
140
137
  def duplicate_local(
141
138
  self,
@@ -172,7 +169,7 @@ class Files:
172
169
 
173
170
  if os.path.exists(new_path):
174
171
  self.window.update_status(
175
- "[ERROR] File already exists: {}".format(os.path.basename(new_path))
172
+ f"[ERROR] File already exists: {os.path.basename(new_path)}"
176
173
  )
177
174
  return
178
175
 
@@ -181,12 +178,12 @@ class Files:
181
178
  else:
182
179
  copy2(path, new_path)
183
180
  self.window.update_status(
184
- "[OK] Duplicated file: {} -> {}".format(os.path.basename(path), name)
181
+ f"[OK] Duplicated file: {os.path.basename(path)} -> {name}"
185
182
  )
186
183
  self.update_explorer()
187
184
  except Exception as e:
188
185
  self.window.core.debug.log(e)
189
- print("Error duplicating file: {} - {}".format(path, e))
186
+ print(f"Error duplicating file: {path} - {e}")
190
187
 
191
188
  def download_local(self, path: str):
192
189
  """
@@ -211,11 +208,11 @@ class Files:
211
208
  else:
212
209
  shutil.copy2(path, files[0])
213
210
  self.window.update_status(
214
- "[OK] Downloaded file: {}".format(os.path.basename(path))
211
+ f"[OK] Downloaded file: {os.path.basename(path)}"
215
212
  )
216
213
  except Exception as e:
217
214
  self.window.core.debug.log(e)
218
- print("Error downloading file: {} - {}".format(path, e))
215
+ print(f"Error downloading file: {path} - {e}")
219
216
 
220
217
  def upload_local(
221
218
  self,
@@ -268,9 +265,9 @@ class Files:
268
265
  num += 1
269
266
  except Exception as e:
270
267
  self.window.core.debug.log(e)
271
- print("Error copying file {}: {}".format(file_path, e))
268
+ print(f"Error copying file {file_path}: {e}")
272
269
  if num > 0:
273
- self.window.update_status("[OK] Uploaded: {} files.".format(num))
270
+ self.window.update_status(f"[OK] Uploaded: {num} files.")
274
271
  self.update_explorer()
275
272
 
276
273
  def rename(self, path: str):
@@ -299,12 +296,12 @@ class Files:
299
296
  new_path = os.path.join(os.path.dirname(path), name)
300
297
  if os.path.exists(new_path):
301
298
  self.window.update_status(
302
- "[ERROR] File already exists: {}".format(os.path.basename(new_path))
299
+ f"[ERROR] File already exists: {os.path.basename(new_path)}"
303
300
  )
304
301
  return
305
302
  os.rename(path, new_path)
306
303
  self.window.update_status(
307
- "[OK] Renamed: {} -> {}".format(os.path.basename(path), name)
304
+ f"[OK] Renamed: {os.path.basename(path)} -> {name}"
308
305
  )
309
306
  self.window.ui.dialog['rename'].close()
310
307
  self.update_explorer()
@@ -328,24 +325,8 @@ class Files:
328
325
 
329
326
  :param path: path to file or directory
330
327
  """
331
- if os.path.isdir(path):
332
- if not self.window.core.platforms.is_snap():
333
- url = QUrl.fromLocalFile(path)
334
- QDesktopServices.openUrl(url)
335
- else:
336
- url = QUrl.fromLocalFile(path)
337
- if not QDesktopServices.openUrl(url):
338
- subprocess.run(['gio', 'open', path])
339
- else:
340
- if not self.window.core.platforms.is_snap():
341
- path = self.window.core.filesystem.get_path(path)
342
- url = QUrl.fromLocalFile(path)
343
- QDesktopServices.openUrl(url)
344
- else:
345
- path = self.window.core.filesystem.get_path(path)
346
- url = QUrl.fromLocalFile(path)
347
- QDesktopServices.openUrl(url)
348
- #subprocess.run(['gio', 'open', path])
328
+ path = self.window.core.filesystem.get_path(path)
329
+ Opener.open_path(path, reveal=False)
349
330
 
350
331
  def open_in_file_manager(
351
332
  self,
@@ -359,20 +340,8 @@ class Files:
359
340
  :param select: select file in file manager
360
341
  """
361
342
  path = self.window.core.filesystem.get_path(path)
362
- if select: # path to file: open containing directory
363
- path = self.window.core.filesystem.get_path(
364
- os.path.dirname(path)
365
- )
366
-
367
343
  if os.path.exists(path):
368
- if not self.window.core.platforms.is_snap():
369
- url = self.window.core.filesystem.get_url(path)
370
- QDesktopServices.openUrl(url)
371
- # show_in_file_manager(path, select)
372
- else:
373
- url = QUrl.fromLocalFile(path)
374
- if not QDesktopServices.openUrl(url):
375
- subprocess.run(['gio', 'open', path])
344
+ Opener.open_path(path, reveal=select)
376
345
 
377
346
  def make_dir_dialog(self, path: str):
378
347
  """
@@ -411,7 +380,7 @@ class Files:
411
380
  return
412
381
  os.makedirs(path_dir, exist_ok=True)
413
382
  self.window.update_status(
414
- "[OK] Directory created: {}".format(name)
383
+ f"[OK] Directory created: {name}"
415
384
  )
416
385
  self.update_explorer()
417
386
 
@@ -473,9 +442,9 @@ class Files:
473
442
  :param path: path to file
474
443
  """
475
444
  if os.path.isdir(path):
476
- cmd = "Please list files from directory: {}".format(self.strip_work_path(path))
445
+ cmd = f"Please list files from directory: {self.strip_work_path(path)}"
477
446
  else:
478
- cmd = "Please read this file from current directory: {}".format(self.strip_work_path(path))
447
+ cmd = f"Please read this file from current directory: {self.strip_work_path(path)}"
479
448
  self.window.controller.chat.common.append_to_input(cmd)
480
449
 
481
450
  def make_ts_prefix(self) -> str: