]>
crepu.dev Git - config.git/blob - djavu-asus/emacs/elpy/rpc-venv/lib/python3.11/site-packages/black/concurrency.py
ce01657839981794b5ee1a2995cf079ac74298c1
2 Formatting many files at once via multiprocessing. Contains entrypoint and utilities.
4 NOTE: this module is only imported if we need to format several files at once.
12 from concurrent
.futures
import Executor
, ProcessPoolExecutor
, ThreadPoolExecutor
13 from multiprocessing
import Manager
14 from pathlib
import Path
15 from typing
import Any
, Iterable
, Optional
, Set
17 from mypy_extensions
import mypyc_attr
19 from black
import WriteBack
, format_file_in_place
20 from black
.cache
import Cache
21 from black
.mode
import Mode
22 from black
.output
import err
23 from black
.report
import Changed
, Report
26 def maybe_install_uvloop() -> None:
27 """If our environment has uvloop installed we use it.
29 This is called only from command-line entry points to avoid
30 interfering with the parent process if Black is used as a library.
40 def cancel(tasks
: Iterable
["asyncio.Task[Any]"]) -> None:
41 """asyncio signal handler that cancels all `tasks` and reports to stderr."""
47 def shutdown(loop
: asyncio
.AbstractEventLoop
) -> None:
48 """Cancel all pending tasks on `loop`, wait for them, and close the loop."""
50 # This part is borrowed from asyncio/runners.py in Python 3.7b2.
51 to_cancel
= [task
for task
in asyncio
.all_tasks(loop
) if not task
.done()]
55 for task
in to_cancel
:
57 loop
.run_until_complete(asyncio
.gather(*to_cancel
, return_exceptions
=True))
59 # `concurrent.futures.Future` objects cannot be cancelled once they
60 # are already running. There might be some when the `shutdown()` happened.
61 # Silence their logger's spew about the event loop being closed.
62 cf_logger
= logging
.getLogger("concurrent.futures")
63 cf_logger
.setLevel(logging
.CRITICAL
)
67 # diff-shades depends on being to monkeypatch this function to operate. I know it's
68 # not ideal, but this shouldn't cause any issues ... hopefully. ~ichard26
69 @mypyc_attr(patchable
=True)
73 write_back
: WriteBack
,
76 workers
: Optional
[int],
78 """Reformat multiple files using a ProcessPoolExecutor."""
79 maybe_install_uvloop()
83 workers
= int(os
.environ
.get("BLACK_NUM_WORKERS", 0))
84 workers
= workers
or os
.cpu_count() or 1
85 if sys
.platform
== "win32":
86 # Work around https://bugs.python.org/issue26903
87 workers
= min(workers
, 60)
89 executor
= ProcessPoolExecutor(max_workers
=workers
)
90 except (ImportError, NotImplementedError, OSError):
91 # we arrive here if the underlying system does not support multi-processing
92 # like in AWS Lambda or Termux, in which case we gracefully fallback to
93 # a ThreadPoolExecutor with just a single worker (more workers would not do us
94 # any good due to the Global Interpreter Lock)
95 executor
= ThreadPoolExecutor(max_workers
=1)
97 loop
= asyncio
.new_event_loop()
98 asyncio
.set_event_loop(loop
)
100 loop
.run_until_complete(
104 write_back
=write_back
,
115 asyncio
.set_event_loop(None)
116 if executor
is not None:
120 async def schedule_formatting(
123 write_back
: WriteBack
,
126 loop
: asyncio
.AbstractEventLoop
,
127 executor
: "Executor",
129 """Run formatting of `sources` in parallel using the provided `executor`.
131 (Use ProcessPoolExecutors for actual parallelism.)
133 `write_back`, `fast`, and `mode` options are passed to
134 :func:`format_file_in_place`.
136 cache
= Cache
.read(mode
)
137 if write_back
not in (WriteBack
.DIFF
, WriteBack
.COLOR_DIFF
):
138 sources
, cached
= cache
.filtered_cached(sources
)
139 for src
in sorted(cached
):
140 report
.done(src
, Changed
.CACHED
)
145 sources_to_cache
= []
147 if write_back
in (WriteBack
.DIFF
, WriteBack
.COLOR_DIFF
):
148 # For diff output, we need locks to ensure we don't interleave output
149 # from different processes.
151 lock
= manager
.Lock()
153 asyncio
.ensure_future(
154 loop
.run_in_executor(
155 executor
, format_file_in_place
, src
, fast
, mode
, write_back
, lock
158 for src
in sorted(sources
)
160 pending
= tasks
.keys()
162 loop
.add_signal_handler(signal
.SIGINT
, cancel
, pending
)
163 loop
.add_signal_handler(signal
.SIGTERM
, cancel
, pending
)
164 except NotImplementedError:
165 # There are no good alternatives for these on Windows.
168 done
, _
= await asyncio
.wait(pending
, return_when
=asyncio
.FIRST_COMPLETED
)
170 src
= tasks
.pop(task
)
172 cancelled
.append(task
)
173 elif task
.exception():
174 report
.failed(src
, str(task
.exception()))
176 changed
= Changed
.YES
if task
.result() else Changed
.NO
177 # If the file was written back or was successfully checked as
178 # well-formatted, store this information in the cache.
179 if write_back
is WriteBack
.YES
or (
180 write_back
is WriteBack
.CHECK
and changed
is Changed
.NO
182 sources_to_cache
.append(src
)
183 report
.done(src
, changed
)
185 await asyncio
.gather(*cancelled
, return_exceptions
=True)
187 cache
.write(sources_to_cache
)