Skip to content

Commit

Permalink
add a hack to avoid signal() erroring in a background thread
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmicexplorer committed Jun 19, 2020
1 parent 985e10e commit 9c0a262
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 10 deletions.
23 changes: 16 additions & 7 deletions src/pip/_internal/cli/progress_bars.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from pip._internal.utils.typing import MYPY_CHECK_RUNNING

if MYPY_CHECK_RUNNING:
from typing import Any, Dict, List
from typing import Any, Dict, List, Optional

try:
from pip._vendor import colorama
Expand All @@ -24,6 +24,18 @@
colorama = None


def _signal_unless_backgrounded(signum, handler):
# type: (int, Any) -> Optional[Any]
try:
return signal(signum, handler)
except ValueError:
# FIXME: this otherwise doesn't work when called from a non-main
# thread. This therefore fails if we try to download more than one
# wheel at once via threading, which calls back to Downloader, which
# uses this progress bar.
return None


def _select_progress_class(preferred, fallback):
# type: (Bar, Bar) -> Bar
encoding = getattr(preferred.file, "encoding", None)
Expand Down Expand Up @@ -84,11 +96,8 @@ def __init__(self, *args, **kwargs):
**kwargs
)

# FIXME: this otherwise doesn't work when called from a non-main
# thread. This therfore fails if we try to download more than one wheel
# at once.
# self.original_handler = signal(SIGINT, self.handle_sigint)
self.original_handler = None
self.original_handler = _signal_unless_backgrounded(
SIGINT, self.handle_sigint)

# If signal() returns None, the previous handler was not installed from
# Python, and we cannot restore it. This probably should not happen,
Expand All @@ -107,7 +116,7 @@ def finish(self):
normally, or gets interrupted.
"""
super(InterruptibleMixin, self).finish() # type: ignore
signal(SIGINT, self.original_handler)
_signal_unless_backgrounded(SIGINT, self.original_handler)

def handle_sigint(self, signum, frame): # type: ignore
"""
Expand Down
14 changes: 12 additions & 2 deletions src/pip/_internal/req/req_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from pip._vendor.packaging.utils import canonicalize_name

from pip._internal.distributions.shallow_wheel import (
DistributionNeedingFinalHydration)
DistributionNeedingFinalHydration,
)
from pip._internal.exceptions import InstallationError
from pip._internal.models.wheel import Wheel
from pip._internal.utils import compatibility_tags
Expand Down Expand Up @@ -66,8 +67,14 @@ def perform_all_final_hydration(self):
if not self.dists_needing_final_hydration:
return

exceptions = []
def do_hydrate(dist):
dist.finally_hydrate()
# type: (DistributionNeedingFinalHydration) -> None
try:
dist.finally_hydrate()
except Exception as e:
exceptions.append(e)

all_threads = [
threading.Thread(
target=do_hydrate, name='download dist {}'.format(dist),
Expand All @@ -78,6 +85,9 @@ def do_hydrate(dist):
t.start()
for t in all_threads:
t.join()
if exceptions:
raise ValueError('at least one thread failed (errors below):\n{}'
.format('\n'.join(str(e) for e in exceptions)))

def add_unnamed_requirement(self, install_req):
# type: (InstallRequirement) -> None
Expand Down
3 changes: 2 additions & 1 deletion src/pip/_internal/resolution/resolvelib/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from pip._vendor.resolvelib import Resolver as RLResolver

from pip._internal.distributions.shallow_wheel import (
DistributionNeedingFinalHydration)
DistributionNeedingFinalHydration,
)
from pip._internal.exceptions import DistributionNotFound, InstallationError
from pip._internal.req.req_set import RequirementSet
from pip._internal.resolution.base import BaseResolver
Expand Down

0 comments on commit 9c0a262

Please sign in to comment.