pygpt-net 2.6.57__py3-none-any.whl → 2.6.59__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 (47) hide show
  1. pygpt_net/CHANGELOG.txt +10 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +30 -25
  4. pygpt_net/controller/debug/debug.py +3 -3
  5. pygpt_net/controller/dialogs/info.py +6 -2
  6. pygpt_net/controller/ui/tabs.py +17 -0
  7. pygpt_net/core/agents/runners/llama_workflow.py +0 -0
  8. pygpt_net/core/filesystem/parser.py +37 -24
  9. pygpt_net/core/filesystem/url.py +5 -2
  10. pygpt_net/data/config/config.json +4 -3
  11. pygpt_net/data/config/models.json +3 -3
  12. pygpt_net/data/config/settings.json +41 -2
  13. pygpt_net/data/js/app/ui.js +1 -1
  14. pygpt_net/data/js/app.min.js +2 -2
  15. pygpt_net/data/locale/locale.de.ini +5 -1
  16. pygpt_net/data/locale/locale.en.ini +5 -1
  17. pygpt_net/data/locale/locale.es.ini +5 -1
  18. pygpt_net/data/locale/locale.fr.ini +5 -1
  19. pygpt_net/data/locale/locale.it.ini +5 -1
  20. pygpt_net/data/locale/locale.pl.ini +5 -1
  21. pygpt_net/data/locale/locale.uk.ini +5 -1
  22. pygpt_net/data/locale/locale.zh.ini +5 -1
  23. pygpt_net/data/locale/plugin.cmd_system.en.ini +68 -0
  24. pygpt_net/js_rc.py +5 -5
  25. pygpt_net/plugin/base/plugin.py +3 -5
  26. pygpt_net/plugin/cmd_system/config.py +377 -1
  27. pygpt_net/plugin/cmd_system/plugin.py +52 -8
  28. pygpt_net/plugin/cmd_system/runner.py +508 -32
  29. pygpt_net/plugin/cmd_system/winapi.py +481 -0
  30. pygpt_net/plugin/cmd_system/worker.py +88 -15
  31. pygpt_net/provider/agents/llama_index/workflow/supervisor.py +0 -0
  32. pygpt_net/provider/core/config/patch.py +8 -1
  33. pygpt_net/provider/llms/openai.py +6 -4
  34. pygpt_net/tools/code_interpreter/ui/html.py +2 -1
  35. pygpt_net/tools/html_canvas/ui/widgets.py +19 -18
  36. pygpt_net/tools/web_browser/__init__.py +12 -0
  37. pygpt_net/tools/web_browser/tool.py +232 -0
  38. pygpt_net/tools/web_browser/ui/__init__.py +0 -0
  39. pygpt_net/tools/web_browser/ui/dialogs.py +123 -0
  40. pygpt_net/tools/web_browser/ui/widgets.py +351 -0
  41. pygpt_net/ui/widget/textarea/html.py +172 -24
  42. pygpt_net/ui/widget/textarea/web.py +1 -1
  43. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/METADATA +81 -61
  44. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/RECORD +45 -39
  45. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/LICENSE +0 -0
  46. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/WHEEL +0 -0
  47. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/entry_points.txt +0 -0
@@ -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: 2024.11.24 06:00:00 #
9
+ # Updated Date: 2025.09.23 07:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.plugin.base.config import BaseConfig, BasePlugin
@@ -49,6 +49,7 @@ class Config(BaseConfig):
49
49
  }
50
50
  ports_items = []
51
51
 
52
+ # Sandbox / sys_exec (original)
52
53
  plugin.add_option(
53
54
  "sandbox_docker",
54
55
  type="bool",
@@ -134,4 +135,379 @@ class Config(BaseConfig):
134
135
  enabled=True,
135
136
  description="Allows system commands execution",
136
137
  tab="general",
138
+ )
139
+
140
+ # -------------------------------
141
+ # WinAPI options (new tab)
142
+ # -------------------------------
143
+ plugin.add_option(
144
+ "winapi_enabled",
145
+ type="bool",
146
+ value=True,
147
+ label="Enable WinAPI",
148
+ description="Enable Windows API features on Microsoft Windows.",
149
+ tab="winapi",
150
+ )
151
+ plugin.add_option(
152
+ "win_keys_per_char_delay_ms",
153
+ type="int",
154
+ value=2,
155
+ label="Keys: per-char delay (ms)",
156
+ description="Delay between characters for win_keys_text.",
157
+ tab="winapi",
158
+ )
159
+ plugin.add_option(
160
+ "win_keys_hold_ms",
161
+ type="int",
162
+ value=50,
163
+ label="Keys: hold (ms)",
164
+ description="Hold duration for modifiers in win_keys_send.",
165
+ tab="winapi",
166
+ )
167
+ plugin.add_option(
168
+ "win_keys_gap_ms",
169
+ type="int",
170
+ value=30,
171
+ label="Keys: gap (ms)",
172
+ description="Gap between normal key taps in win_keys_send.",
173
+ tab="winapi",
174
+ )
175
+ plugin.add_option(
176
+ "win_drag_step_delay_ms",
177
+ type="int",
178
+ value=10,
179
+ label="Drag: step delay (ms)",
180
+ description="Delay between intermediate drag steps in win_drag.",
181
+ tab="winapi",
182
+ )
183
+
184
+ # -------------------------------
185
+ # WinAPI commands
186
+ # -------------------------------
187
+ plugin.add_cmd(
188
+ "win_list",
189
+ instruction="List top-level windows. You can filter by title substring.",
190
+ params=[
191
+ {"name": "filter_title", "type": "str", "description": "Substring to filter by window title", "required": False},
192
+ {"name": "visible_only", "type": "bool", "description": "Only visible windows", "required": False},
193
+ {"name": "limit", "type": "int", "description": "Limit number of results", "required": False},
194
+ ],
195
+ enabled=True,
196
+ description="List top-level windows",
197
+ tab="winapi",
198
+ )
199
+ plugin.add_cmd(
200
+ "win_find",
201
+ instruction="Find windows by multiple attributes.",
202
+ params=[
203
+ {"name": "title", "type": "str", "description": "Title or substring", "required": False},
204
+ {"name": "class_name", "type": "str", "description": "Exact class name", "required": False},
205
+ {"name": "exe", "type": "str", "description": "Process executable name", "required": False},
206
+ {"name": "pid", "type": "int", "description": "Process ID", "required": False},
207
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
208
+ {"name": "visible_only", "type": "bool", "description": "Only visible", "required": False},
209
+ ],
210
+ enabled=True,
211
+ description="Find windows",
212
+ tab="winapi",
213
+ )
214
+ plugin.add_cmd(
215
+ "win_children",
216
+ instruction="List child windows for a given parent HWND.",
217
+ params=[{"name": "hwnd", "type": "int", "description": "Parent window handle", "required": True}],
218
+ enabled=True,
219
+ description="List child windows",
220
+ tab="winapi",
221
+ )
222
+ plugin.add_cmd(
223
+ "win_foreground",
224
+ instruction="Return info about the current foreground window.",
225
+ params=[],
226
+ enabled=True,
227
+ description="Foreground window info",
228
+ tab="winapi",
229
+ )
230
+ plugin.add_cmd(
231
+ "win_rect",
232
+ instruction="Return window rectangle (geometry).",
233
+ params=[
234
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
235
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
236
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
237
+ ],
238
+ enabled=True,
239
+ description="Get window rect",
240
+ tab="winapi",
241
+ )
242
+ plugin.add_cmd(
243
+ "win_get_state",
244
+ instruction="Return full window state and metadata.",
245
+ params=[
246
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
247
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
248
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
249
+ ],
250
+ enabled=True,
251
+ description="Get window state",
252
+ tab="winapi",
253
+ )
254
+ plugin.add_cmd(
255
+ "win_focus",
256
+ instruction="Bring a window to foreground.",
257
+ params=[
258
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
259
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
260
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
261
+ ],
262
+ enabled=True,
263
+ description="Set focus to a window",
264
+ tab="winapi",
265
+ )
266
+ plugin.add_cmd(
267
+ "win_move_resize",
268
+ instruction="Move and/or resize a window. Omit any of x,y,width,height to keep current.",
269
+ params=[
270
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
271
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
272
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
273
+ {"name": "x", "type": "int", "description": "Left position", "required": False},
274
+ {"name": "y", "type": "int", "description": "Top position", "required": False},
275
+ {"name": "width", "type": "int", "description": "Width", "required": False},
276
+ {"name": "height", "type": "int", "description": "Height", "required": False},
277
+ ],
278
+ enabled=True,
279
+ description="Move/resize window",
280
+ tab="winapi",
281
+ )
282
+ plugin.add_cmd(
283
+ "win_minimize",
284
+ instruction="Minimize a window.",
285
+ params=[
286
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
287
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
288
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
289
+ ],
290
+ enabled=True,
291
+ description="Minimize window",
292
+ tab="winapi",
293
+ )
294
+ plugin.add_cmd(
295
+ "win_maximize",
296
+ instruction="Maximize a window.",
297
+ params=[
298
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
299
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
300
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
301
+ ],
302
+ enabled=True,
303
+ description="Maximize window",
304
+ tab="winapi",
305
+ )
306
+ plugin.add_cmd(
307
+ "win_restore",
308
+ instruction="Restore a minimized or maximized window.",
309
+ params=[
310
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
311
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
312
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
313
+ ],
314
+ enabled=True,
315
+ description="Restore window",
316
+ tab="winapi",
317
+ )
318
+ plugin.add_cmd(
319
+ "win_close",
320
+ instruction="Close a window (sends WM_CLOSE).",
321
+ params=[
322
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
323
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
324
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
325
+ ],
326
+ enabled=True,
327
+ description="Close window",
328
+ tab="winapi",
329
+ )
330
+ plugin.add_cmd(
331
+ "win_show",
332
+ instruction="Show a window.",
333
+ params=[
334
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
335
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
336
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
337
+ ],
338
+ enabled=True,
339
+ description="Show window",
340
+ tab="winapi",
341
+ )
342
+ plugin.add_cmd(
343
+ "win_hide",
344
+ instruction="Hide a window.",
345
+ params=[
346
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
347
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
348
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
349
+ ],
350
+ enabled=True,
351
+ description="Hide window",
352
+ tab="winapi",
353
+ )
354
+ plugin.add_cmd(
355
+ "win_always_on_top",
356
+ instruction="Toggle window always-on-top (topmost).",
357
+ params=[
358
+ {"name": "topmost", "type": "bool", "description": "True to set, False to clear", "required": True},
359
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
360
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
361
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
362
+ ],
363
+ enabled=True,
364
+ description="Always on top",
365
+ tab="winapi",
366
+ )
367
+ plugin.add_cmd(
368
+ "win_set_opacity",
369
+ instruction="Set window opacity using layered style. Provide alpha (0..255) OR opacity (0..1).",
370
+ params=[
371
+ {"name": "alpha", "type": "int", "description": "Alpha 0..255", "required": False},
372
+ {"name": "opacity", "type": "float", "description": "Opacity 0..1", "required": False},
373
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
374
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
375
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
376
+ ],
377
+ enabled=True,
378
+ description="Set window opacity",
379
+ tab="winapi",
380
+ )
381
+ plugin.add_cmd(
382
+ "win_screenshot",
383
+ instruction="Take a window screenshot and save to a PNG file. Returns absolute path.",
384
+ params=[
385
+ {"name": "hwnd", "type": "int", "description": "Target window handle", "required": False},
386
+ {"name": "title", "type": "str", "description": "Title substring to match", "required": False},
387
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
388
+ {"name": "path", "type": "str", "description": "Output path (relative to data/ if not absolute)", "required": False},
389
+ ],
390
+ enabled=True,
391
+ description="Window screenshot to PNG",
392
+ tab="winapi",
393
+ )
394
+ plugin.add_cmd(
395
+ "win_area_screenshot",
396
+ instruction="Take a rectangular screenshot of the screen or relative to a window.",
397
+ params=[
398
+ {"name": "x", "type": "int", "description": "Left", "required": True},
399
+ {"name": "y", "type": "int", "description": "Top", "required": True},
400
+ {"name": "width", "type": "int", "description": "Width", "required": True},
401
+ {"name": "height", "type": "int", "description": "Height", "required": True},
402
+ {"name": "hwnd", "type": "int", "description": "Base window (optional)", "required": False},
403
+ {"name": "title", "type": "str", "description": "Base window by title (optional)", "required": False},
404
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
405
+ {"name": "relative", "type": "bool", "description": "Coords relative to window when hwnd/title provided", "required": False},
406
+ {"name": "path", "type": "str", "description": "Output path", "required": False},
407
+ ],
408
+ enabled=True,
409
+ description="Area screenshot to PNG",
410
+ tab="winapi",
411
+ )
412
+ plugin.add_cmd(
413
+ "win_clipboard_get",
414
+ instruction="Get clipboard text.",
415
+ params=[],
416
+ enabled=True,
417
+ description="Clipboard get",
418
+ tab="winapi",
419
+ )
420
+ plugin.add_cmd(
421
+ "win_clipboard_set",
422
+ instruction="Set clipboard text.",
423
+ params=[{"name": "text", "type": "str", "description": "Text to set", "required": True}],
424
+ enabled=True,
425
+ description="Clipboard set",
426
+ tab="winapi",
427
+ )
428
+ plugin.add_cmd(
429
+ "win_cursor_get",
430
+ instruction="Get cursor position.",
431
+ params=[],
432
+ enabled=True,
433
+ description="Cursor get",
434
+ tab="winapi",
435
+ )
436
+ plugin.add_cmd(
437
+ "win_cursor_set",
438
+ instruction="Set cursor position.",
439
+ params=[
440
+ {"name": "x", "type": "int", "description": "X coordinate", "required": True},
441
+ {"name": "y", "type": "int", "description": "Y coordinate", "required": True},
442
+ ],
443
+ enabled=True,
444
+ description="Cursor set",
445
+ tab="winapi",
446
+ )
447
+ plugin.add_cmd(
448
+ "win_keys_text",
449
+ instruction="Type Unicode text into the active window (uses SendInput).",
450
+ params=[
451
+ {"name": "text", "type": "str", "description": "Text to type", "required": True},
452
+ {"name": "per_char_delay_ms", "type": "int", "description": "Delay between characters in ms", "required": False},
453
+ ],
454
+ enabled=True,
455
+ description="Type text",
456
+ tab="winapi",
457
+ )
458
+ plugin.add_cmd(
459
+ "win_keys_send",
460
+ instruction="Send key combinations, e.g. ['CTRL','ALT','T'] or ['F5'].",
461
+ params=[
462
+ {"name": "keys", "type": "list", "description": "List of key tokens", "required": True},
463
+ {"name": "hold_ms", "type": "int", "description": "Hold duration for modifiers", "required": False},
464
+ {"name": "gap_ms", "type": "int", "description": "Gap between taps", "required": False},
465
+ ],
466
+ enabled=True,
467
+ description="Send key combos",
468
+ tab="winapi",
469
+ )
470
+ plugin.add_cmd(
471
+ "win_click",
472
+ instruction="Click at a screen point or relative to a window.",
473
+ params=[
474
+ {"name": "x", "type": "int", "description": "X coordinate", "required": True},
475
+ {"name": "y", "type": "int", "description": "Y coordinate", "required": True},
476
+ {"name": "button", "type": "str", "description": "left/right/middle", "required": False},
477
+ {"name": "double", "type": "bool", "description": "Double click", "required": False},
478
+ {"name": "hwnd", "type": "int", "description": "Base window", "required": False},
479
+ {"name": "title", "type": "str", "description": "Base window by title", "required": False},
480
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
481
+ {"name": "relative", "type": "bool", "description": "Coords relative to window", "required": False},
482
+ ],
483
+ enabled=True,
484
+ description="Mouse click",
485
+ tab="winapi",
486
+ )
487
+ plugin.add_cmd(
488
+ "win_drag",
489
+ instruction="Drag from (x1,y1) to (x2,y2), absolute or relative to a window.",
490
+ params=[
491
+ {"name": "x1", "type": "int", "description": "Start X", "required": True},
492
+ {"name": "y1", "type": "int", "description": "Start Y", "required": True},
493
+ {"name": "x2", "type": "int", "description": "End X", "required": True},
494
+ {"name": "y2", "type": "int", "description": "End Y", "required": True},
495
+ {"name": "hwnd", "type": "int", "description": "Base window", "required": False},
496
+ {"name": "title", "type": "str", "description": "Base window by title", "required": False},
497
+ {"name": "exact", "type": "bool", "description": "Exact title match", "required": False},
498
+ {"name": "relative", "type": "bool", "description": "Coords relative to window", "required": False},
499
+ {"name": "steps", "type": "int", "description": "Interpolation steps", "required": False},
500
+ {"name": "hold_ms", "type": "int", "description": "Delay between steps (ms)", "required": False},
501
+ ],
502
+ enabled=True,
503
+ description="Mouse drag",
504
+ tab="winapi",
505
+ )
506
+ plugin.add_cmd(
507
+ "win_monitors",
508
+ instruction="List monitors/screens and their geometry.",
509
+ params=[],
510
+ enabled=True,
511
+ description="List monitors",
512
+ tab="winapi",
137
513
  )
@@ -6,9 +6,11 @@
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.15 23:00:00 #
9
+ # Updated Date: 2025.09.23 07:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ import platform
13
+
12
14
  from pygpt_net.plugin.base.plugin import BasePlugin
13
15
  from pygpt_net.core.events import Event
14
16
  from pygpt_net.item.ctx import CtxItem
@@ -32,9 +34,45 @@ class Plugin(BasePlugin):
32
34
  'os',
33
35
  ]
34
36
  self.order = 100
37
+
38
+ # Core command(s)
39
+ self.winapi_cmds = [
40
+ # Windows window/query
41
+ "win_list",
42
+ "win_find",
43
+ "win_children",
44
+ "win_foreground",
45
+ "win_rect",
46
+ "win_get_state",
47
+ # Window control
48
+ "win_focus",
49
+ "win_move_resize",
50
+ "win_minimize",
51
+ "win_maximize",
52
+ "win_restore",
53
+ "win_close",
54
+ "win_show",
55
+ "win_hide",
56
+ "win_always_on_top",
57
+ "win_set_opacity",
58
+ # Screenshots
59
+ "win_screenshot",
60
+ "win_area_screenshot",
61
+ # Clipboard / input / cursor / monitors
62
+ "win_clipboard_get",
63
+ "win_clipboard_set",
64
+ "win_cursor_get",
65
+ "win_cursor_set",
66
+ "win_keys_text",
67
+ "win_keys_send",
68
+ "win_click",
69
+ "win_drag",
70
+ "win_monitors",
71
+ ]
35
72
  self.allowed_cmds = [
36
73
  "sys_exec",
37
- ]
74
+ ] + self.winapi_cmds
75
+
38
76
  self.use_locale = True
39
77
  self.docker = Docker(self)
40
78
  self.runner = Runner(self)
@@ -81,20 +119,26 @@ class Plugin(BasePlugin):
81
119
  :param data: event data dict
82
120
  """
83
121
  # get current working directory
84
- os = self.window.core.platforms.get_as_string(env_suffix=False)
122
+ os_name = self.window.core.platforms.get_as_string(env_suffix=False)
85
123
  cwd = self.window.core.config.get_user_dir('data')
86
- if self.get_option_value("sandbox_docker"):
87
- cwd = "/data (in docker sandbox, mapped on our host machine to: {})".format(cwd)
88
- os = "Linux" # docker image
124
+ is_windows = (platform.system() == "Windows")
125
+ winapi_enabled = self.get_option_value("winapi_enabled")
126
+
89
127
  for item in self.allowed_cmds:
128
+ # Gate WinAPI commands to Windows platform (and enabled flag)
129
+ if item in self.winapi_cmds:
130
+ if not is_windows or not winapi_enabled:
131
+ continue
132
+
90
133
  if self.has_cmd(item):
91
134
  cmd = self.get_cmd(item)
135
+ # Keep original sys_exec instruction enhancement
92
136
  if self.get_option_value("auto_cwd") and item == "sys_exec":
93
137
  cmd["instruction"] += "\nIMPORTANT: ALWAYS use absolute (not relative) path when passing " \
94
138
  "ANY command to \"command\" param. Current workdir is: {cwd}. " \
95
139
  "Current OS is: {os}".format(
96
140
  cwd=cwd,
97
- os=os)
141
+ os=os_name)
98
142
  data['cmd'].append(cmd) # append command
99
143
 
100
144
  def cmd(self, ctx: CtxItem, cmds: list, silent: bool = False):
@@ -162,4 +206,4 @@ class Plugin(BasePlugin):
162
206
  worker.run_async()
163
207
 
164
208
  except Exception as e:
165
- self.error(e)
209
+ self.error(e)