pyqt-code-editor 1.0.5__tar.gz → 1.1.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.
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/PKG-INFO +1 -1
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/__init__.py +1 -1
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/manager.py +109 -23
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/COPYING +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyproject.toml +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/_settings.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/app.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/code_editors.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/generic.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/javascript.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/markdown.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/python.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/text.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/editor_panel.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/find_in_files.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/jupyter_console/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/jupyter_console/jupyter_console.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/jupyter_console/jupyter_console_tab.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/jupyter_console/kernel_spec_manager.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/project_explorer.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/settings_panel.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/sigmund/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/sigmund/confirm_run_code_dialog.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/sigmund/editor_workspace.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/sigmund/sigmund.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/sigmund/sigmund_analyst_chat_widget.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/sigmund/sigmund_analyst_widget.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/workspace_explorer.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/environment_manager.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/auto_indent.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/auto_pair.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/base.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/check.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/comment.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/complete.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/execute.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/file_link.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/highlight_matching_brackets.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/line_number.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/merge_undo_actions.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/python_auto_indent.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/search_replace.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/shortcuts.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/smart_backspace_delete.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/symbols.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/theme.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/widgets/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/zoom.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/sigmund-analyst.png +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/signal_router.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/syntax_highlighters/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/syntax_highlighters/languages/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/syntax_highlighters/languages/generic.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/syntax_highlighters/languages/python.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/syntax_highlighters/syntax_highlighter.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/themes.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/utils/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/utils/languages/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/utils/languages/python/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/utils/languages/python/_auto_indent.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/utils/languages/python/_extract_cells.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/utils/languages/python/_mask_str_in_code.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/watchdog.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/calltip_widget.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/completion_popup.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/dock.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/quick_open_dialog.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/quick_open_file_dialog.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/quick_symbol_dialog.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/search_replace_frame.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/tab_splitter.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/tabbed_editor.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/languages/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/languages/generic.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/languages/python.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/process.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/__init__.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/codestral.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/jedi.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/ruff.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/sigmund.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/symbol.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/tree_sitter.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/settings.py +0 -0
- {pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/readme.md +0 -0
|
@@ -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,29 +38,24 @@ 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
|
-
def
|
|
46
|
+
def _start_new_worker(is_free: bool = False) -> int:
|
|
42
47
|
"""
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
Create and start a single new worker process, send it the current
|
|
49
|
+
settings, and register it in _workers and _starting.
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
`is_free` controls whether the worker is immediately marked as
|
|
52
|
+
available for reuse (used by start_worker_pool(), which starts idle
|
|
53
|
+
workers ahead of time) or not (used by send_worker_request(), which
|
|
54
|
+
immediately queues a real request on it).
|
|
48
55
|
|
|
49
|
-
|
|
56
|
+
Returns the new worker's pid. Does not check MAX_CONCURRENT_STARTING;
|
|
57
|
+
callers are responsible for that.
|
|
50
58
|
"""
|
|
51
|
-
if suspended:
|
|
52
|
-
return None, None
|
|
53
|
-
# 1. Look for an existing free worker
|
|
54
|
-
for pid, w in list(_workers.items()):
|
|
55
|
-
if w["is_free"] and w["process"].is_alive():
|
|
56
|
-
logger.info(f"Reusing free worker {pid} (of {len(_workers)}) for request {list(data.keys())}")
|
|
57
|
-
w["is_free"] = False
|
|
58
|
-
w["request_queue"].put(data)
|
|
59
|
-
return w["result_queue"], pid
|
|
60
|
-
|
|
61
|
-
# 2. If no free worker was found, create a new one.
|
|
62
59
|
request_queue = Queue()
|
|
63
60
|
result_queue = Queue()
|
|
64
61
|
p = Process(target=main_worker_process_function,
|
|
@@ -71,27 +68,108 @@ def send_worker_request(**data) -> (Queue, int):
|
|
|
71
68
|
"process": p,
|
|
72
69
|
"request_queue": request_queue,
|
|
73
70
|
"result_queue": result_queue,
|
|
74
|
-
"is_free":
|
|
71
|
+
"is_free": is_free,
|
|
75
72
|
}
|
|
73
|
+
_starting.add(pid)
|
|
76
74
|
|
|
77
|
-
logger.info(f"
|
|
75
|
+
logger.info(f"Created new worker {pid} (is_free={is_free})")
|
|
78
76
|
settings_action = {'action': 'set_settings',
|
|
79
77
|
'settings': {name: value for name, value in settings}}
|
|
80
78
|
request_queue.put(settings_action)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
return pid
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def send_worker_request(**data) -> (Queue, int):
|
|
83
|
+
"""
|
|
84
|
+
Send a request to a worker process. If a free worker is available,
|
|
85
|
+
reuse it; otherwise create a new one. Return (result_queue, pid).
|
|
86
|
+
|
|
87
|
+
The caller can poll the result_queue for responses, and once done,
|
|
88
|
+
call mark_worker_as_free(pid) to release this worker for future use.
|
|
89
|
+
|
|
90
|
+
If workers are suspended, return (None, None).
|
|
91
|
+
|
|
92
|
+
We also decline to create a new worker (returning (None, None)) if
|
|
93
|
+
MAX_CONCURRENT_STARTING workers are already "starting" -- i.e. have
|
|
94
|
+
been created but haven't yet completed a first successful round-trip
|
|
95
|
+
(see _starting / mark_worker_as_free()). This caps how many freshly
|
|
96
|
+
spawned, still-booting worker processes can pile up at once. A single
|
|
97
|
+
worker creation still pays the normal (and, on Windows, sometimes
|
|
98
|
+
substantial) process-creation cost on the GUI thread, but we avoid the
|
|
99
|
+
much worse case of several such creations happening back-to-back and
|
|
100
|
+
competing for CPU/disk/antivirus scanning at the same time.
|
|
101
|
+
|
|
102
|
+
Note that start_worker_pool() shares the same _starting bookkeeping,
|
|
103
|
+
so a pool worker that is still booting also counts against this cap.
|
|
104
|
+
"""
|
|
105
|
+
if suspended:
|
|
106
|
+
return None, None
|
|
107
|
+
# 1. Look for an existing free worker. This also picks up workers that
|
|
108
|
+
# were started ahead of time by start_worker_pool(), whether or not
|
|
109
|
+
# they have finished booting yet.
|
|
110
|
+
for pid, w in list(_workers.items()):
|
|
111
|
+
if w["is_free"] and w["process"].is_alive():
|
|
112
|
+
logger.info(f"Reusing free worker {pid} (of {len(_workers)}) for request {list(data.keys())}")
|
|
113
|
+
w["is_free"] = False
|
|
114
|
+
w["request_queue"].put(data)
|
|
115
|
+
return w["result_queue"], pid
|
|
116
|
+
|
|
117
|
+
# 2. If no free worker was found, create a new one -- unless too many
|
|
118
|
+
# workers are already in the process of starting up.
|
|
119
|
+
if len(_starting) >= MAX_CONCURRENT_STARTING:
|
|
120
|
+
logger.info(
|
|
121
|
+
f"Declining to start a new worker for request "
|
|
122
|
+
f"{list(data.keys())}; {len(_starting)} worker(s) already "
|
|
123
|
+
"starting."
|
|
124
|
+
)
|
|
125
|
+
return None, None
|
|
126
|
+
|
|
127
|
+
pid = _start_new_worker(is_free=False)
|
|
128
|
+
w = _workers[pid]
|
|
129
|
+
logger.info(f"Sending request {data['action']} to newly created worker {pid}")
|
|
130
|
+
w["request_queue"].put(data)
|
|
131
|
+
return w["result_queue"], pid
|
|
132
|
+
|
|
133
|
+
def start_worker_pool():
|
|
134
|
+
"""
|
|
135
|
+
Proactively start up to MAX_CONCURRENT_STARTING idle worker processes,
|
|
136
|
+
so that a free (or at least already-booting) worker is more likely to
|
|
137
|
+
be available by the time the user actually triggers a request -- e.g.
|
|
138
|
+
right when they start typing.
|
|
139
|
+
|
|
140
|
+
Workers started here are tracked in _starting exactly like workers
|
|
141
|
+
created on-demand by send_worker_request(), and are marked as free
|
|
142
|
+
immediately, so send_worker_request() will pick them up as soon as
|
|
143
|
+
they exist -- whether or not they've finished booting yet.
|
|
144
|
+
|
|
145
|
+
Intended to be called at strategic moments (e.g. app startup, after
|
|
146
|
+
resume(), or when a new editor is opened), not from a tight loop: each
|
|
147
|
+
call may create up to MAX_CONCURRENT_STARTING new processes on top of
|
|
148
|
+
whatever is already starting.
|
|
149
|
+
"""
|
|
150
|
+
if suspended:
|
|
151
|
+
logger.info("Not starting worker pool because workers are suspended.")
|
|
152
|
+
return
|
|
153
|
+
for _ in range(MAX_CONCURRENT_STARTING):
|
|
154
|
+
_start_new_worker(is_free=True)
|
|
155
|
+
logger.info(f"Started worker pool of {MAX_CONCURRENT_STARTING} worker(s).")
|
|
84
156
|
|
|
85
157
|
def mark_worker_as_free(pid: int):
|
|
86
158
|
"""
|
|
87
159
|
Mark a previously-used worker process (identified by pid)
|
|
88
160
|
as free for reuse. If the worker has died, clean it up instead.
|
|
161
|
+
|
|
162
|
+
This is also the point at which a worker is considered to have proven
|
|
163
|
+
itself alive-and-useful (it has completed a request), so we release
|
|
164
|
+
its "starting" slot here if it still held one -- whether it succeeded
|
|
165
|
+
or died in the process.
|
|
89
166
|
"""
|
|
90
167
|
w = _workers.get(pid)
|
|
91
168
|
if w is None:
|
|
92
169
|
return
|
|
93
170
|
if w["process"].is_alive():
|
|
94
171
|
w["is_free"] = True
|
|
172
|
+
_starting.discard(pid)
|
|
95
173
|
logger.info(f"Marking worker {pid} as free")
|
|
96
174
|
else:
|
|
97
175
|
# The worker died while handling a request; clean up its resources
|
|
@@ -99,6 +177,7 @@ def mark_worker_as_free(pid: int):
|
|
|
99
177
|
_workers.pop(pid)
|
|
100
178
|
_close_worker_queues(w)
|
|
101
179
|
w["process"].join(timeout=1)
|
|
180
|
+
_starting.discard(pid)
|
|
102
181
|
|
|
103
182
|
def check_worker_alive(pid: int) -> bool:
|
|
104
183
|
w = _workers.get(pid)
|
|
@@ -128,7 +207,7 @@ def reap_stopping_workers():
|
|
|
128
207
|
logger.warning(f"Error joining stopped worker {pid}: {e}")
|
|
129
208
|
_close_worker_queues(w)
|
|
130
209
|
|
|
131
|
-
def stop_unused_workers(max_free: int =
|
|
210
|
+
def stop_unused_workers(max_free: int = 3, force: bool = False):
|
|
132
211
|
"""
|
|
133
212
|
Request that free worker processes stop until there is at most
|
|
134
213
|
'max_free' free processes left. This keeps us from accumulating too
|
|
@@ -143,6 +222,11 @@ def stop_unused_workers(max_free: int = 1, force: bool = False):
|
|
|
143
222
|
joining a process that hasn't exited yet can block for a noticeable
|
|
144
223
|
amount of time, especially on Windows, and this function is typically
|
|
145
224
|
called from a periodic timer on the main/GUI thread.
|
|
225
|
+
|
|
226
|
+
Note: if max_free is set lower than MAX_CONCURRENT_STARTING, workers
|
|
227
|
+
just started by start_worker_pool() may be asked to stop again before
|
|
228
|
+
they ever get used. The default of 3 leaves headroom above
|
|
229
|
+
MAX_CONCURRENT_STARTING (2).
|
|
146
230
|
"""
|
|
147
231
|
global _last_stop_unused_time
|
|
148
232
|
if not force and time.time() - _last_stop_unused_time < STOP_UNUSED_INTERVAL:
|
|
@@ -197,6 +281,8 @@ def stop_all_workers():
|
|
|
197
281
|
logger.warning(f"Error joining stopping worker {pid}: {e}")
|
|
198
282
|
_close_worker_queues(w)
|
|
199
283
|
del _stopping[pid]
|
|
284
|
+
# Nothing is left running, so no worker can still be "starting".
|
|
285
|
+
_starting.clear()
|
|
200
286
|
logger.info("All workers stopped.")
|
|
201
287
|
|
|
202
288
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/code_editors.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/generic.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/python.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/code_editors/languages/text.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/editor_panel.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/find_in_files.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/project_explorer.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/settings_panel.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/sigmund/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/sigmund/sigmund.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/components/workspace_explorer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/merge_undo_actions.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/python_auto_indent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/smart_backspace_delete.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/mixins/widgets/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/syntax_highlighters/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/utils/languages/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/calltip_widget.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/completion_popup.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/quick_open_dialog.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/quick_open_file_dialog.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/quick_symbol_dialog.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/widgets/search_replace_frame.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/languages/__init__.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/languages/generic.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/languages/python.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/__init__.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/codestral.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/sigmund.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/symbol.py
RENAMED
|
File without changes
|
{pyqt_code_editor-1.0.5 → pyqt_code_editor-1.1.0}/pyqt_code_editor/worker/providers/tree_sitter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|