Skip to content

Commit 63ad2bd

Browse files
authored
Merge branch '2.1' into patch-1
2 parents 1eb79f0 + 0fa82cf commit 63ad2bd

File tree

13 files changed

+77
-11
lines changed

13 files changed

+77
-11
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from invoke import Collection
2+
3+
# Issue #934 (from #919) only seems to trigger on this style of 'from . import
4+
# xxx' - a vanilla self-contained tasks/__init__.py is still fine!
5+
from . import module
6+
7+
ns = Collection(module)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from invoke import task
2+
3+
4+
@task
5+
def mytask(c):
6+
print("hi!")

integration/main.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ def bad_collection_exits_nonzero(self):
6161
assert not result.stdout
6262
assert result.stderr
6363

64+
@trap
65+
def package_style_collections_internally_importable(self):
66+
# After merging #919 blew this up and unit tests did not detect!
67+
result = run("cd package && inv -l")
68+
assert "mytask" in result.stdout
69+
6470
def loads_real_user_config(self):
6571
path = os.path.expanduser("~/.invoke.yaml")
6672
try:

invoke/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version_info__ = (2, 1, 0)
1+
__version_info__ = (2, 1, 1)
22
__version__ = ".".join(map(str, __version_info__))

invoke/loader.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def load(self, name: Optional[str] = None) -> Tuple[ModuleType, str]:
7777
sys.path.insert(0, path)
7878
# Actual import
7979
module = module_from_spec(spec)
80+
sys.modules[spec.name] = module # so 'from . import xxx' works
8081
spec.loader.exec_module(module)
8182
return module, os.path.dirname(spec.origin)
8283
msg = "ImportError loading {!r}, raising ImportError"

invoke/runners.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,12 @@ def start(self, command: str, shell: str, env: Dict[str, Any]) -> None:
13461346

13471347
def kill(self) -> None:
13481348
pid = self.pid if self.using_pty else self.process.pid
1349-
os.kill(pid, signal.SIGKILL)
1349+
try:
1350+
os.kill(pid, signal.SIGKILL)
1351+
except ProcessLookupError:
1352+
# In odd situations where our subprocess is already dead, don't
1353+
# throw this upwards.
1354+
pass
13501355

13511356
@property
13521357
def process_is_finished(self) -> bool:
@@ -1385,6 +1390,7 @@ def returncode(self) -> Optional[int]:
13851390
return self.process.returncode
13861391

13871392
def stop(self) -> None:
1393+
super().stop()
13881394
# If we opened a PTY for child communications, make sure to close() it,
13891395
# otherwise long-running Invoke-using processes exhaust their file
13901396
# descriptors eventually.

sites/www/changelog.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ Changelog
55
- :support:`936 backported` Make sure ``py.typed`` is in our packaging
66
manifest; without it, users working from a regular installation
77
can't perform type checks. Thanks to Nikita Sobolev for catch & patch.
8+
- :release:`2.1.1 <2023-05-01>`
9+
- :bug:`934` The `importlib` upgrade in 2.1 had a corner case bug (regarding
10+
``from . import <submodule>`` functionality within package-like task trees)
11+
which in turn exposed a false-pass in our test suite. Both have now been
12+
fixed. Thanks to Greg Meyer and Robert J. Berger for the bug reports.
13+
- :release:`2.0.1 <2023-04-29>`
14+
- :bug:`910` Add more rigor around subprocess/runner shutdown to avoid spurious
15+
exceptions & also fix downstream issues in libraries like Fabric. Reported by
16+
Orlando Rodríguez.
817
- :release:`2.1.0 <2023-04-28>`
918
- :support:`675` Implement `importlib` and deprecate `imp` module. Patches
1019
provided by Jesse P. Johnson

tests/_support/namespacing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from invoke import Collection, task, call
22

3-
from package import module
3+
from subspace import module
44

55

66
@task

tests/_support/package/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from invoke import Collection
2+
3+
from . import module
4+
5+
ns = Collection(module)

tests/_support/subspace/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from invoke import Collection
2+
3+
from . import module
4+
5+
ns = Collection(module)

tests/_support/subspace/module.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from invoke import task
2+
3+
4+
@task
5+
def mytask(c):
6+
pass

tests/loader.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import sys
33
from importlib.util import spec_from_file_location
44
from types import ModuleType
5+
from pathlib import Path
56

67
from pytest import raises
78

@@ -50,7 +51,7 @@ def adds_module_parent_dir_to_sys_path(self):
5051
# Crummy doesn't-explode test.
5152
_BasicLoader().load("namespacing")
5253

53-
def doesnt_dupliate_parent_dir_addition(self):
54+
def doesnt_duplicate_parent_dir_addition(self):
5455
_BasicLoader().load("namespacing")
5556
_BasicLoader().load("namespacing")
5657
# If the bug is present, this will be 2 at least (and often more, since
@@ -59,8 +60,12 @@ def doesnt_dupliate_parent_dir_addition(self):
5960

6061
def can_load_package(self):
6162
loader = _BasicLoader()
62-
# make sure it doesn't explode
63-
loader.load("package")
63+
# Load itself doesn't explode (tests 'from . import xxx' internally)
64+
mod, loc = loader.load("package")
65+
# Properties of returned values look as expected
66+
package = Path(support) / "package"
67+
assert loc == str(package)
68+
assert mod.__file__ == str(package / "__init__.py")
6469

6570
def load_name_defaults_to_config_tasks_collection_name(self):
6671
"load() name defaults to config.tasks.collection_name"

tests/runners.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,11 +1402,6 @@ def run_always_stops_timer(self):
14021402
runner.run(_)
14031403
runner._timer.cancel.assert_called_once_with()
14041404

1405-
def stop_cancels_timer(self):
1406-
runner = self._mocked_timer()
1407-
runner.stop()
1408-
runner._timer.cancel.assert_called_once_with()
1409-
14101405
def timer_aliveness_is_test_of_timing_out(self):
14111406
# Might be redundant, but easy enough to unit test
14121407
runner = Runner(Context())
@@ -1430,6 +1425,12 @@ def always_runs_no_matter_what(self):
14301425
runner.run(_)
14311426
runner.stop.assert_called_once_with()
14321427

1428+
def cancels_timer(self):
1429+
runner = self._runner()
1430+
runner._timer = Mock()
1431+
runner.stop()
1432+
runner._timer.cancel.assert_called_once_with()
1433+
14331434
class asynchronous:
14341435
def returns_Promise_immediately_and_finishes_on_join(self):
14351436
# Dummy subclass with controllable process_is_finished flag
@@ -1534,6 +1535,15 @@ def _run(self, *args, **kwargs):
15341535
def _runner(self, *args, **kwargs):
15351536
return _runner(*args, **dict(kwargs, klass=_FastLocal))
15361537

1538+
class stop:
1539+
@mock_subprocess()
1540+
def calls_super(self):
1541+
# Re #910
1542+
runner = self._runner()
1543+
runner._timer = Mock() # twiddled by parent class stop()
1544+
runner.run(_)
1545+
runner._timer.cancel.assert_called_once_with()
1546+
15371547
class pty:
15381548
@mock_pty()
15391549
def when_pty_True_we_use_pty_fork_and_os_exec(self):

0 commit comments

Comments
 (0)