• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

psf / black / 7692220850

29 Jan 2024 06:46AM UTC coverage: 96.45%. Remained the same
7692220850

Pull #4192

github

web-flow
Bump peter-evans/create-or-update-comment from 3.1.0 to 4.0.0

Bumps [peter-evans/create-or-update-comment](https://github.com/peter-evans/create-or-update-comment) from 3.1.0 to 4.0.0.
- [Release notes](https://github.com/peter-evans/create-or-update-comment/releases)
- [Commits](https://github.com/peter-evans/create-or-update-comment/compare/23ff15729...71345be02)

---
updated-dependencies:
- dependency-name: peter-evans/create-or-update-comment
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #4192: Bump peter-evans/create-or-update-comment from 3.1.0 to 4.0.0

3021 of 3232 branches covered (0.0%)

7145 of 7408 relevant lines covered (96.45%)

4.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.54
/src/black/concurrency.py
1
"""
2
Formatting many files at once via multiprocessing. Contains entrypoint and utilities.
3

4
NOTE: this module is only imported if we need to format several files at once.
5
"""
6

7
import asyncio
5✔
8
import logging
5✔
9
import os
5✔
10
import signal
5✔
11
import sys
5✔
12
import traceback
5✔
13
from concurrent.futures import Executor, ProcessPoolExecutor, ThreadPoolExecutor
5✔
14
from multiprocessing import Manager
5✔
15
from pathlib import Path
5✔
16
from typing import Any, Iterable, Optional, Set
5✔
17

18
from mypy_extensions import mypyc_attr
5✔
19

20
from black import WriteBack, format_file_in_place
5✔
21
from black.cache import Cache
5✔
22
from black.mode import Mode
5✔
23
from black.output import err
5✔
24
from black.report import Changed, Report
5✔
25

26

27
def maybe_install_uvloop() -> None:
5✔
28
    """If our environment has uvloop installed we use it.
29

30
    This is called only from command-line entry points to avoid
31
    interfering with the parent process if Black is used as a library.
32
    """
33
    try:
5✔
34
        import uvloop
5✔
35

36
        uvloop.install()
×
37
    except ImportError:
5✔
38
        pass
5✔
39

40

41
def cancel(tasks: Iterable["asyncio.Future[Any]"]) -> None:
5✔
42
    """asyncio signal handler that cancels all `tasks` and reports to stderr."""
43
    err("Aborted!")
×
44
    for task in tasks:
×
45
        task.cancel()
×
46

47

48
def shutdown(loop: asyncio.AbstractEventLoop) -> None:
5✔
49
    """Cancel all pending tasks on `loop`, wait for them, and close the loop."""
50
    try:
5✔
51
        # This part is borrowed from asyncio/runners.py in Python 3.7b2.
52
        to_cancel = [task for task in asyncio.all_tasks(loop) if not task.done()]
5✔
53
        if not to_cancel:
5!
54
            return
5✔
55

56
        for task in to_cancel:
×
57
            task.cancel()
×
58
        loop.run_until_complete(asyncio.gather(*to_cancel, return_exceptions=True))
×
59
    finally:
60
        # `concurrent.futures.Future` objects cannot be cancelled once they
61
        # are already running. There might be some when the `shutdown()` happened.
62
        # Silence their logger's spew about the event loop being closed.
63
        cf_logger = logging.getLogger("concurrent.futures")
5✔
64
        cf_logger.setLevel(logging.CRITICAL)
5✔
65
        loop.close()
5✔
66

67

68
# diff-shades depends on being to monkeypatch this function to operate. I know it's
69
# not ideal, but this shouldn't cause any issues ... hopefully. ~ichard26
70
@mypyc_attr(patchable=True)
5✔
71
def reformat_many(
5✔
72
    sources: Set[Path],
73
    fast: bool,
74
    write_back: WriteBack,
75
    mode: Mode,
76
    report: Report,
77
    workers: Optional[int],
78
) -> None:
79
    """Reformat multiple files using a ProcessPoolExecutor."""
80
    maybe_install_uvloop()
5✔
81

82
    executor: Executor
83
    if workers is None:
5!
84
        workers = int(os.environ.get("BLACK_NUM_WORKERS", 0))
5✔
85
        workers = workers or os.cpu_count() or 1
5✔
86
    if sys.platform == "win32":
5!
87
        # Work around https://bugs.python.org/issue26903
88
        workers = min(workers, 60)
×
89
    try:
5✔
90
        executor = ProcessPoolExecutor(max_workers=workers)
5✔
91
    except (ImportError, NotImplementedError, OSError):
×
92
        # we arrive here if the underlying system does not support multi-processing
93
        # like in AWS Lambda or Termux, in which case we gracefully fallback to
94
        # a ThreadPoolExecutor with just a single worker (more workers would not do us
95
        # any good due to the Global Interpreter Lock)
96
        executor = ThreadPoolExecutor(max_workers=1)
×
97

98
    loop = asyncio.new_event_loop()
5✔
99
    asyncio.set_event_loop(loop)
5✔
100
    try:
5✔
101
        loop.run_until_complete(
5✔
102
            schedule_formatting(
103
                sources=sources,
104
                fast=fast,
105
                write_back=write_back,
106
                mode=mode,
107
                report=report,
108
                loop=loop,
109
                executor=executor,
110
            )
111
        )
112
    finally:
113
        try:
5✔
114
            shutdown(loop)
5✔
115
        finally:
116
            asyncio.set_event_loop(None)
5✔
117
        if executor is not None:
5!
118
            executor.shutdown()
5✔
119

120

121
async def schedule_formatting(
5✔
122
    sources: Set[Path],
123
    fast: bool,
124
    write_back: WriteBack,
125
    mode: Mode,
126
    report: "Report",
127
    loop: asyncio.AbstractEventLoop,
128
    executor: "Executor",
129
) -> None:
130
    """Run formatting of `sources` in parallel using the provided `executor`.
131

132
    (Use ProcessPoolExecutors for actual parallelism.)
133

134
    `write_back`, `fast`, and `mode` options are passed to
135
    :func:`format_file_in_place`.
136
    """
137
    cache = Cache.read(mode)
5✔
138
    if write_back not in (WriteBack.DIFF, WriteBack.COLOR_DIFF):
5✔
139
        sources, cached = cache.filtered_cached(sources)
5✔
140
        for src in sorted(cached):
5✔
141
            report.done(src, Changed.CACHED)
5✔
142
    if not sources:
5!
143
        return
×
144

145
    cancelled = []
5✔
146
    sources_to_cache = []
5✔
147
    lock = None
5✔
148
    if write_back in (WriteBack.DIFF, WriteBack.COLOR_DIFF):
5✔
149
        # For diff output, we need locks to ensure we don't interleave output
150
        # from different processes.
151
        manager = Manager()
5✔
152
        lock = manager.Lock()
5✔
153
    tasks = {
5✔
154
        asyncio.ensure_future(
155
            loop.run_in_executor(
156
                executor, format_file_in_place, src, fast, mode, write_back, lock
157
            )
158
        ): src
159
        for src in sorted(sources)
160
    }
161
    pending = tasks.keys()
5✔
162
    try:
5✔
163
        loop.add_signal_handler(signal.SIGINT, cancel, pending)
5✔
164
        loop.add_signal_handler(signal.SIGTERM, cancel, pending)
5✔
165
    except NotImplementedError:
×
166
        # There are no good alternatives for these on Windows.
167
        pass
×
168
    while pending:
5✔
169
        done, _ = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
5✔
170
        for task in done:
5✔
171
            src = tasks.pop(task)
5✔
172
            if task.cancelled():
5!
173
                cancelled.append(task)
×
174
            elif exc := task.exception():
5✔
175
                if report.verbose:
5!
176
                    traceback.print_exception(type(exc), exc, exc.__traceback__)
5✔
177
                report.failed(src, str(exc))
5✔
178
            else:
179
                changed = Changed.YES if task.result() else Changed.NO
5✔
180
                # If the file was written back or was successfully checked as
181
                # well-formatted, store this information in the cache.
182
                if write_back is WriteBack.YES or (
5✔
183
                    write_back is WriteBack.CHECK and changed is Changed.NO
184
                ):
185
                    sources_to_cache.append(src)
5✔
186
                report.done(src, changed)
5✔
187
    if cancelled:
5!
188
        await asyncio.gather(*cancelled, return_exceptions=True)
×
189
    if sources_to_cache:
5✔
190
        cache.write(sources_to_cache)
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc