pyqt-code-editor 1.0.5__tar.gz → 1.0.6__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.
Files changed (91) hide show
  1. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/PKG-INFO +1 -1
  2. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/__init__.py +1 -1
  3. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/manager.py +33 -3
  4. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/COPYING +0 -0
  5. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyproject.toml +0 -0
  6. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/_settings.py +0 -0
  7. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/app.py +0 -0
  8. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/code_editors/__init__.py +0 -0
  9. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/code_editors/code_editors.py +0 -0
  10. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/code_editors/languages/__init__.py +0 -0
  11. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/code_editors/languages/generic.py +0 -0
  12. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/code_editors/languages/javascript.py +0 -0
  13. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/code_editors/languages/markdown.py +0 -0
  14. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/code_editors/languages/python.py +0 -0
  15. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/code_editors/languages/text.py +0 -0
  16. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/__init__.py +0 -0
  17. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/editor_panel.py +0 -0
  18. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/find_in_files.py +0 -0
  19. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/jupyter_console/__init__.py +0 -0
  20. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/jupyter_console/jupyter_console.py +0 -0
  21. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/jupyter_console/jupyter_console_tab.py +0 -0
  22. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/jupyter_console/kernel_spec_manager.py +0 -0
  23. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/project_explorer.py +0 -0
  24. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/settings_panel.py +0 -0
  25. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/sigmund/__init__.py +0 -0
  26. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/sigmund/confirm_run_code_dialog.py +0 -0
  27. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/sigmund/editor_workspace.py +0 -0
  28. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/sigmund/sigmund.py +0 -0
  29. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/sigmund/sigmund_analyst_chat_widget.py +0 -0
  30. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/sigmund/sigmund_analyst_widget.py +0 -0
  31. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/components/workspace_explorer.py +0 -0
  32. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/environment_manager.py +0 -0
  33. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/__init__.py +0 -0
  34. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/auto_indent.py +0 -0
  35. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/auto_pair.py +0 -0
  36. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/base.py +0 -0
  37. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/check.py +0 -0
  38. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/comment.py +0 -0
  39. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/complete.py +0 -0
  40. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/execute.py +0 -0
  41. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/file_link.py +0 -0
  42. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/highlight_matching_brackets.py +0 -0
  43. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/line_number.py +0 -0
  44. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/merge_undo_actions.py +0 -0
  45. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/python_auto_indent.py +0 -0
  46. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/search_replace.py +0 -0
  47. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/shortcuts.py +0 -0
  48. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/smart_backspace_delete.py +0 -0
  49. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/symbols.py +0 -0
  50. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/theme.py +0 -0
  51. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/widgets/__init__.py +0 -0
  52. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/mixins/zoom.py +0 -0
  53. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/sigmund-analyst.png +0 -0
  54. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/signal_router.py +0 -0
  55. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/syntax_highlighters/__init__.py +0 -0
  56. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/syntax_highlighters/languages/__init__.py +0 -0
  57. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/syntax_highlighters/languages/generic.py +0 -0
  58. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/syntax_highlighters/languages/python.py +0 -0
  59. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/syntax_highlighters/syntax_highlighter.py +0 -0
  60. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/themes.py +0 -0
  61. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/utils/__init__.py +0 -0
  62. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/utils/languages/__init__.py +0 -0
  63. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/utils/languages/python/__init__.py +0 -0
  64. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/utils/languages/python/_auto_indent.py +0 -0
  65. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/utils/languages/python/_extract_cells.py +0 -0
  66. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/utils/languages/python/_mask_str_in_code.py +0 -0
  67. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/watchdog.py +0 -0
  68. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/__init__.py +0 -0
  69. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/calltip_widget.py +0 -0
  70. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/completion_popup.py +0 -0
  71. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/dock.py +0 -0
  72. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/quick_open_dialog.py +0 -0
  73. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/quick_open_file_dialog.py +0 -0
  74. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/quick_symbol_dialog.py +0 -0
  75. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/search_replace_frame.py +0 -0
  76. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/tab_splitter.py +0 -0
  77. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/widgets/tabbed_editor.py +0 -0
  78. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/__init__.py +0 -0
  79. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/languages/__init__.py +0 -0
  80. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/languages/generic.py +0 -0
  81. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/languages/python.py +0 -0
  82. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/process.py +0 -0
  83. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/providers/__init__.py +0 -0
  84. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/providers/codestral.py +0 -0
  85. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/providers/jedi.py +0 -0
  86. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/providers/ruff.py +0 -0
  87. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/providers/sigmund.py +0 -0
  88. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/providers/symbol.py +0 -0
  89. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/providers/tree_sitter.py +0 -0
  90. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/pyqt_code_editor/worker/settings.py +0 -0
  91. {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.0.6}/readme.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyqt_code_editor
3
- Version: 1.0.5
3
+ Version: 1.0.6
4
4
  Summary: Fully featured code-editor widgets for PyQt
5
5
  Keywords: code editor,pyqt,ide
6
6
  Author-email: Sebastiaan Mathôt <s.mathot@cogsci.nl>
@@ -2,4 +2,4 @@
2
2
 
3
3
  from ._settings import settings
4
4
 
5
- __version__ = '1.0.5'
5
+ __version__ = '1.0.6'
@@ -5,9 +5,11 @@ from .process import main_worker_process_function
5
5
  from .. import watchdog, settings
6
6
  logger = logging.getLogger(__name__)
7
7
  STOP_UNUSED_INTERVAL = 10
8
+ MAX_CONCURRENT_STARTING = 2
8
9
  _last_stop_unused_time = 0
9
10
  _workers = {} # pid -> {"process", "request_queue", "result_queue", "is_free"}
10
11
  _stopping = {} # pid -> same shape as _workers, but already asked to quit
12
+ _starting = set() # pids of workers created but not yet proven alive-and-useful
11
13
  suspended = False
12
14
 
13
15
 
@@ -36,6 +38,9 @@ def _cleanup_dead_workers():
36
38
  w["process"].join(timeout=1)
37
39
  except Exception as e:
38
40
  logger.warning(f"Error joining dead worker {pid}: {e}")
41
+ # If this worker died before ever completing its first request, it
42
+ # was still occupying a "starting" slot; free that slot up.
43
+ _starting.discard(pid)
39
44
 
40
45
 
41
46
  def send_worker_request(**data) -> (Queue, int):
@@ -47,7 +52,17 @@ def send_worker_request(**data) -> (Queue, int):
47
52
  call mark_worker_as_free(pid) to release this worker for future use.
48
53
 
49
54
  If workers are suspended, return (None, None).
50
- """
55
+
56
+ We also decline to create a new worker (returning (None, None)) if
57
+ MAX_CONCURRENT_STARTING workers are already "starting" -- i.e. have
58
+ been created but haven't yet completed a first successful round-trip
59
+ (see _starting / mark_worker_as_free()). This caps how many freshly
60
+ spawned, still-booting worker processes can pile up at once. A single
61
+ worker creation still pays the normal (and, on Windows, sometimes
62
+ substantial) process-creation cost on the GUI thread, but we avoid the
63
+ much worse case of several such creations happening back-to-back and
64
+ competing for CPU/disk/antivirus scanning at the same time.
65
+ """
51
66
  if suspended:
52
67
  return None, None
53
68
  # 1. Look for an existing free worker
@@ -58,7 +73,12 @@ def send_worker_request(**data) -> (Queue, int):
58
73
  w["request_queue"].put(data)
59
74
  return w["result_queue"], pid
60
75
 
61
- # 2. If no free worker was found, create a new one.
76
+ # 2. If no free worker was found, create a new one -- unless too many
77
+ # workers are already in the process of starting up.
78
+ if len(_starting) >= MAX_CONCURRENT_STARTING:
79
+ logger.info("declining requst, because too many worker(s) already starting.")
80
+ return None, None
81
+
62
82
  request_queue = Queue()
63
83
  result_queue = Queue()
64
84
  p = Process(target=main_worker_process_function,
@@ -73,6 +93,7 @@ def send_worker_request(**data) -> (Queue, int):
73
93
  "result_queue": result_queue,
74
94
  "is_free": False,
75
95
  }
96
+ _starting.add(pid)
76
97
 
77
98
  logger.info(f"Creating new worker {pid} for request {data['action']}")
78
99
  settings_action = {'action': 'set_settings',
@@ -86,12 +107,18 @@ def mark_worker_as_free(pid: int):
86
107
  """
87
108
  Mark a previously-used worker process (identified by pid)
88
109
  as free for reuse. If the worker has died, clean it up instead.
110
+
111
+ This is also the point at which a worker is considered to have proven
112
+ itself alive-and-useful (it has completed a request), so we release
113
+ its "starting" slot here if it still held one -- whether it succeeded
114
+ or died in the process.
89
115
  """
90
116
  w = _workers.get(pid)
91
117
  if w is None:
92
118
  return
93
119
  if w["process"].is_alive():
94
120
  w["is_free"] = True
121
+ _starting.discard(pid)
95
122
  logger.info(f"Marking worker {pid} as free")
96
123
  else:
97
124
  # The worker died while handling a request; clean up its resources
@@ -99,6 +126,7 @@ def mark_worker_as_free(pid: int):
99
126
  _workers.pop(pid)
100
127
  _close_worker_queues(w)
101
128
  w["process"].join(timeout=1)
129
+ _starting.discard(pid)
102
130
 
103
131
  def check_worker_alive(pid: int) -> bool:
104
132
  w = _workers.get(pid)
@@ -128,7 +156,7 @@ def reap_stopping_workers():
128
156
  logger.warning(f"Error joining stopped worker {pid}: {e}")
129
157
  _close_worker_queues(w)
130
158
 
131
- def stop_unused_workers(max_free: int = 1, force: bool = False):
159
+ def stop_unused_workers(max_free: int = 3, force: bool = False):
132
160
  """
133
161
  Request that free worker processes stop until there is at most
134
162
  'max_free' free processes left. This keeps us from accumulating too
@@ -197,6 +225,8 @@ def stop_all_workers():
197
225
  logger.warning(f"Error joining stopping worker {pid}: {e}")
198
226
  _close_worker_queues(w)
199
227
  del _stopping[pid]
228
+ # Nothing is left running, so no worker can still be "starting".
229
+ _starting.clear()
200
230
  logger.info("All workers stopped.")
201
231
 
202
232