1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
import os
import sys
from importlib.util import spec_from_file_location
from types import ModuleType
from pathlib import Path
from pytest import raises
from invoke import Config
from invoke.loader import Loader, FilesystemLoader as FSLoader
from invoke.exceptions import CollectionNotFound
from _util import support
class _BasicLoader(Loader):
"""
Tests top level Loader behavior with basic finder stub.
Used when we want to make sure we're testing Loader.load and not e.g.
FilesystemLoader's specific implementation.
"""
def find(self, name):
path = os.path.join(support, name)
if os.path.exists(f"{path}.py"):
path = f"{path}.py"
elif os.path.exists(path):
path = os.path.join(path, "__init__.py")
spec = spec_from_file_location(name, path)
return spec
class Loader_:
def exhibits_default_config_object(self):
loader = _BasicLoader()
assert isinstance(loader.config, Config)
assert loader.config.tasks.collection_name == "tasks"
def returns_module_and_location(self):
mod, path = _BasicLoader().load("namespacing")
assert isinstance(mod, ModuleType)
assert path == support
def may_configure_config_via_constructor(self):
config = Config({"tasks": {"collection_name": "mytasks"}})
loader = _BasicLoader(config=config)
assert loader.config.tasks.collection_name == "mytasks"
def adds_module_parent_dir_to_sys_path(self):
# Crummy doesn't-explode test.
_BasicLoader().load("namespacing")
def doesnt_duplicate_parent_dir_addition(self):
_BasicLoader().load("namespacing")
_BasicLoader().load("namespacing")
# If the bug is present, this will be 2 at least (and often more, since
# other tests will pollute it (!).
assert sys.path.count(support) == 1
def can_load_package(self):
loader = _BasicLoader()
# Load itself doesn't explode (tests 'from . import xxx' internally)
mod, enclosing_dir = loader.load("package")
# Properties of returned values look as expected
# (enclosing dir is always the one above the module-or-package)
assert enclosing_dir == support
assert mod.__file__ == str(Path(support) / "package" / "__init__.py")
def load_name_defaults_to_config_tasks_collection_name(self):
"load() name defaults to config.tasks.collection_name"
class MockLoader(_BasicLoader):
def find(self, name):
# Sanity
assert name == "simple_ns_list"
return super().find(name)
config = Config({"tasks": {"collection_name": "simple_ns_list"}})
loader = MockLoader(config=config)
# More sanity: expect simple_ns_list.py (not tasks.py)
mod, path = loader.load()
assert mod.__file__ == os.path.join(support, "simple_ns_list.py")
class FilesystemLoader_:
def setup_method(self):
self.loader = FSLoader(start=support)
def discovery_start_point_defaults_to_cwd(self):
assert FSLoader().start == os.getcwd()
def exposes_start_point_as_attribute(self):
assert FSLoader().start == os.getcwd()
def start_point_is_configurable_via_kwarg(self):
start = "/tmp"
assert FSLoader(start=start).start == start
def start_point_is_configurable_via_config(self):
config = Config({"tasks": {"search_root": "nowhere"}})
assert FSLoader(config=config).start == "nowhere"
def raises_CollectionNotFound_if_not_found(self):
with raises(CollectionNotFound):
self.loader.load("nope")
def raises_ImportError_if_found_collection_cannot_be_imported(self):
# Instead of masking with a CollectionNotFound
with raises(ModuleNotFoundError):
self.loader.load("oops")
# TODO: Need CollectionImportError here
def searches_towards_root_of_filesystem(self):
# Loaded while root is in same dir as .py
directly = self.loader.load("foo")
# Loaded while root is multiple dirs deeper than the .py
deep = os.path.join(support, "ignoreme", "ignoremetoo")
indirectly = FSLoader(start=deep).load("foo")
assert directly[0].__file__ == indirectly[0].__file__
assert directly[0].__spec__ == indirectly[0].__spec__
assert directly[1] == indirectly[1]
|