def percolates_to_subcollection_names(self): @task def my_task(c): pass coll = Collection(inner_coll=Collection(my_task)) contexts = coll.to_contexts() assert contexts[0].name == 'inner-coll.my-task'
def sibling_subcollections_ignored(self): inner = Collection('inner', self.task) inner.configure({'foo': 'hi there'}) inner2 = Collection('inner2', Task(_func, name='task2')) inner2.configure({'foo': 'nope'}) root = Collection(inner, inner2) eq_(root.configuration('inner.task')['foo'], 'hi there') eq_(root.configuration('inner2.task2')['foo'], 'nope')
def kwargs_act_as_name_args_for_given_objects(self): sub = Collection() @task def task1(ctx): pass ns = Collection(loltask=task1, notsub=sub) eq_(ns['loltask'], task1) eq_(ns.collections['notsub'], sub)
def sibling_subcollections_ignored(self): inner = Collection("inner", self.task) inner.configure({"foo": "hi there"}) inner2 = Collection("inner2", Task(_func, name="task2")) inner2.configure({"foo": "nope"}) root = Collection(inner, inner2) assert root.configuration("inner.task")["foo"] == "hi there" assert root.configuration("inner2.task2")["foo"] == "nope"
def raises_ValueError_if_collection_without_name(self): # Aka non-root collections must either have an explicit name given # via kwarg, have a name attribute set, or be a module with # __name__ defined. root = Collection() sub = Collection() with raises(ValueError): root.add_collection(sub)
def invalid_subcollection_paths_result_in_KeyError(self): # Straight up invalid with raises(KeyError): Collection("meh").configuration("nope.task") # Exists but wrong level (should be 'root.task', not just # 'task') inner = Collection("inner", self.task) with raises(KeyError): Collection("root", inner).configuration("task")
def invalid_subcollection_paths_result_in_KeyError(self): # Straight up invalid assert_raises(KeyError, Collection('meh').configuration, 'nope.task') # Exists but wrong level (should be 'root.task', not just # 'task') inner = Collection('inner', self.task) assert_raises(KeyError, Collection('root', inner).configuration, 'task')
def setup(self): mod = load('explicit_root') mod.ns.configure({'key': 'builtin', 'otherkey': 'yup'}) mod.ns.name = 'builtin_name' self.unchanged = Collection.from_module(mod) self.changed = Collection.from_module( mod, name='override_name', config={'key': 'override'} )
def access_merges_from_subcollections(self): inner = Collection('inner') inner.configure({'foo': 'bar'}) outer = Collection() outer.configure({'biz': 'baz'}) # With no inner collection eq_(set(outer.configuration.keys()), set(['biz'])) # With inner collection outer.add_collection(inner) eq_(set(outer.configuration.keys()), set(['foo', 'biz']))
def kwargs_act_as_name_args_for_given_objects(self): sub = Collection() @task def task1(c): pass ns = Collection(loltask=task1, notsub=sub) assert ns["loltask"] == task1 assert ns.collections["notsub"] == sub
def percolates_to_subcollection_tasks(self): @task def outer_task(c): pass @task def inner_task(c): pass coll = Collection(outer_task, inner=Collection(inner_task)) contexts = coll.to_contexts() expected = set(['outer-task', 'inner.inner-task']) assert set(x.name for x in contexts) == expected
def keys_dont_have_to_exist_in_full_path(self): # Kinda duplicates earlier stuff; meh # Key only stored on leaf leaf = Collection('leaf', self.task) leaf.configure({'key': 'leaf-value'}) middle = Collection('middle', leaf) root = Collection('root', middle) eq_(root.configuration('middle.leaf.task'), {'key': 'leaf-value'}) # Key stored on mid + leaf but not root middle.configure({'key': 'whoa'}) eq_(root.configuration('middle.leaf.task'), {'key': 'whoa'})
def subcollection_config_works_with_default_tasks(self): @ctask(default=True) def mytask(ctx): eq_(ctx['my.config.key'], 'value') # Sets up a task "known as" sub.mytask which may be called as just # 'sub' due to being default. sub = Collection('sub', mytask=mytask) sub.configure({'my.config.key': 'value'}) main = Collection(sub=sub) # Execute via collection default 'task' name. Executor(collection=main, context=Context()).execute('sub')
def leading_and_trailing_underscores_are_not_affected(self): @task def _what_evers_(c): pass @task def _inner_cooler_(c): pass inner = Collection('inner', _inner_cooler_) contexts = Collection(_what_evers_, inner).to_contexts() expected = ['_what-evers_', 'inner._inner-cooler_'] assert set(x.name for x in contexts) == set(expected)
def returns_unique_Collection_objects_for_same_input_module(self): # Ignoring self.c for now, just in case it changes later. # First, a module with no root NS mod = load('integration') c1 = Collection.from_module(mod) c2 = Collection.from_module(mod) assert c1 is not c2 # Now one *with* a root NS (which was previously buggy) mod2 = load('explicit_root') c3 = Collection.from_module(mod2) c4 = Collection.from_module(mod2) assert c3 is not c4
def keys_dont_have_to_exist_in_full_path(self): # Kinda duplicates earlier stuff; meh # Key only stored on leaf leaf = Collection("leaf", self.task) leaf.configure({"key": "leaf-value"}) middle = Collection("middle", leaf) root = Collection("root", middle) config = root.configuration("middle.leaf.task") assert config == {"key": "leaf-value"} # Key stored on mid + leaf but not root middle.configure({"key": "whoa"}) assert root.configuration("middle.leaf.task") == {"key": "whoa"}
def leading_and_trailing_underscores_are_not_affected(self): @task def _what_evers_(c): pass @task def _inner_cooler_(c): pass inner = Collection("inner", _inner_cooler_) contexts = Collection(_what_evers_, inner).to_contexts() expected = {"_what-evers_", "inner._inner-cooler_"} assert {x.name for x in contexts} == expected
def percolates_to_subcollection_tasks(self): @task def outer_task(c): pass @task def inner_task(c): pass coll = Collection(outer_task, inner=Collection(inner_task)) contexts = coll.to_contexts() expected = {"outer-task", "inner.inner-task"} assert {x.name for x in contexts} == expected
def hands_task_specific_configuration_to_context(self): @ctask def mytask(ctx): eq_(ctx['my.config.key'], 'value') @ctask def othertask(ctx): eq_(ctx['my.config.key'], 'othervalue') inner1 = Collection('inner1', mytask) inner1.configure({'my.config.key': 'value'}) inner2 = Collection('inner2', othertask) inner2.configure({'my.config.key': 'othervalue'}) c = Collection(inner1, inner2) e = Executor(collection=c, context=Context()) e.execute('inner1.mytask', 'inner2.othertask')
def _meh(self): @task def task1(c): pass @task def task2(c): pass @task def task3(c): pass submeh = Collection("submeh", task3) return Collection("meh", task1, task2, submeh)
def submodule_names_are_stripped_to_last_chunk(self): with support_path(): from package import module c = Collection.from_module(module) assert module.__name__ == "package.module" assert c.name == "module" assert "mytask" in c # Sanity
def name_docstring_default_and_tasks(self): expected = dict( name="deploy", help="How to deploy our code and configs.", tasks=[ dict( name="db", help="Deploy to our database servers.", aliases=["db-servers"], ), dict( name="everywhere", help="Deploy to all targets.", aliases=[], ), dict( name="web", help="Update and bounce the webservers.", aliases=[], ), ], default="everywhere", collections=[], ) with support_path(): from tree import deploy coll = Collection.from_module(deploy) assert expected == coll.serialized()
def submodule_names_are_stripped_to_last_chunk(self): with support_path(): from package import module c = Collection.from_module(module) assert module.__name__ == 'package.module' assert c.name == 'module' assert 'mytask' in c # Sanity
def honors_subcollection_default_tasks_on_subcollection_name(self): sub = Collection.from_module(load("decorators")) self.c.add_collection(sub) # Sanity assert self.c["decorators.biz"] is sub["biz"] # Real test assert self.c["decorators"] is self.c["decorators.biz"]
def honors_subcollection_default_tasks_on_subcollection_name(self): sub = Collection.from_module(load('decorator')) self.c.add_collection(sub) # Sanity assert self.c['decorator.biz'] is sub['biz'] # Real test assert self.c['decorator'] is self.c['decorator.biz']
def submodule_names_are_stripped_to_last_chunk(self): with support_path(): from package import module c = Collection.from_module(module) eq_(module.__name__, 'package.module') eq_(c.name, 'module') assert 'mytask' in c # Sanity
def context_names_automatically_become_dashed(self): @task def my_task(c): pass contexts = Collection(my_task).to_contexts() assert contexts[0].name == 'my-task'
def _call_objs(self, contextualized): # Setup pre_body, post_body = Mock(), Mock() t1 = Task(pre_body, contextualized=contextualized) t2 = Task(post_body, contextualized=contextualized) t3 = Task( Mock(), pre=[call(t1, 5, foo='bar')], post=[call(t2, 7, biz='baz')], ) c = Collection(t1=t1, t2=t2, t3=t3) e = Executor(collection=c) e.execute('t3') # Pre-task asserts args, kwargs = pre_body.call_args eq_(kwargs, {'foo': 'bar'}) if contextualized: assert isinstance(args[0], Context) eq_(args[1], 5) else: eq_(args, (5, )) # Post-task asserts args, kwargs = post_body.call_args eq_(kwargs, {'biz': 'baz'}) if contextualized: assert isinstance(args[0], Context) eq_(args[1], 7) else: eq_(args, (7, ))
def honors_subcollection_default_tasks_on_subcollection_name(self): sub = Collection.from_module(load('decorators')) self.c.add_collection(sub) # Sanity assert self.c['decorators.biz'] is sub['biz'] # Real test assert self.c['decorators'] is self.c['decorators.biz']
def _nested_underscores(self, auto_dash_names=None): @task(aliases=['other_name']) def my_task(c): pass @task(aliases=['other_inner']) def inner_task(c): pass # NOTE: explicitly not giving kwarg to subcollection; this # tests that the top-level namespace performs the inverse # transformation when necessary. sub = Collection('inner_coll', inner_task) return Collection(my_task, sub, auto_dash_names=auto_dash_names)
def aliases_are_dashed_too(self): @task(aliases=['hi_im_underscored']) def whatever(c): pass contexts = Collection(whatever).to_contexts() assert 'hi-im-underscored' in contexts[0].aliases
def empty_named_collection(self): expected = dict(name="foo", help=None, tasks=[], default=None, collections=[]) assert expected == Collection("foo").serialized()
def invalid_path(self): # This is really just testing Lexicon/dict behavior but w/e, good # to be explicit, esp if we ever want this to become Exit or # another custom exception. (For now most/all callers manually # catch KeyError and raise Exit just to keep most Exit use high up # in the stack...) with raises(KeyError): collection = Collection.from_module(load('tree')) collection.subcollection_from_path('lol.whatever.man')
def setup(self): mod = load("explicit_root") mod.ns.configure( { "key": "builtin", "otherkey": "yup", "subconfig": {"mykey": "myvalue"}, } ) mod.ns.name = "builtin_name" self.unchanged = Collection.from_module(mod) self.changed = Collection.from_module( mod, name="override_name", config={ "key": "override", "subconfig": {"myotherkey": "myothervalue"}, }, )
def is_valid_package(package_name): """ Checks if a package at site directory has tasks. """ try: apackage = import_module('%s.tasks'%package_name) except ImportError: return False tasks = Collection.from_module(apackage).task_names if tasks == {}: return False return True
def run_easypy_task(argv): """ Run task in easypy. """ from easypy import tasks tasks = Collection.from_module(tasks).task_names if len(argv) == 1: # the request is in the format $ py # display available tasks in easypy display_easypy_tasks() else: # the request is in the format $ py <task> task = argv[1] if not task in tasks.keys(): raise TaskNotAvailable(task) cli.dispatch(prepare_args(argv))
def transforms_are_applied_to_explicit_module_namespaces(self): # Symptom when bug present: Collection.to_contexts() dies # because it iterates over .task_names (transformed) and then # tries to use results to access __getitem__ (no auto # transform...because in all other situations, task structure # keys are already transformed; but this wasn't the case for # from_module() with explicit 'ns' objects!) namespace = self._nested_underscores() class FakeModule(object): __name__ = 'my_module' ns = namespace coll = Collection.from_module( FakeModule(), auto_dash_names=False ) # NOTE: underscores, not dashes expected = {'my_task', 'inner_coll.inner_task'} assert {x.name for x in coll.to_contexts()} == expected
def nested_path(self): collection = Collection.from_module(load('tree')) docs = collection.collections['build'].collections['docs'] assert collection.subcollection_from_path('build.docs') is docs
def top_level_path(self): collection = Collection.from_module(load('tree')) build = collection.collections['build'] assert collection.subcollection_from_path('build') is build
def setup(self): self.c = Collection.from_module(load('explicit_root'))
def top_level_path(self): collection = Collection.from_module(load("tree")) build = collection.collections["build"] assert collection.subcollection_from_path("build") is build
def honors_explicit_collections(self): coll = Collection.from_module(load("explicit_root")) assert "top-level" in coll.tasks assert "sub-level" in coll.collections # The real key test assert "sub-task" not in coll.tasks
def setup(self): self.c = Collection.from_module(load('integration'))
def name_docstring_default_tasks_and_collections(self): docs = dict( name="docs", help="Tasks for managing Sphinx docs.", tasks=[ dict( name="all", help="Build all doc formats.", aliases=[], ), dict( name="html", help="Build HTML output only.", aliases=[], ), dict( name="pdf", help="Build PDF output only.", aliases=[], ), ], default="all", collections=[], ) python = dict( name="python", help="PyPI/etc distribution artifacts.", tasks=[ dict( name="all", help="Build all Python packages.", aliases=[], ), dict( name="sdist", help="Build classic style tar.gz.", aliases=[], ), dict( name="wheel", help="Build a wheel.", aliases=[], ), ], default="all", collections=[], ) expected = dict( name="build", help="Tasks for compiling static code and assets.", tasks=[ dict( name="all", help="Build all necessary artifacts.", aliases=["everything"], ), dict( name="c-ext", help="Build our internal C extension.", aliases=["ext"], ), dict( name="zap", help="A silly way to clean.", aliases=[], ), ], default="all", collections=[docs, python], ) with support_path(): from tree import build coll = Collection.from_module(build) assert expected == coll.serialized()
def honors_explicit_collections(self): coll = Collection.from_module(load('explicit_root')) assert 'top-level' in coll.tasks assert 'sub-level' in coll.collections # The real key test assert 'sub-task' not in coll.tasks
def allows_tasks_with_explicit_names_to_override_bound_name(self): coll = Collection.from_module(load('subcollection_task_name')) assert 'explicit-name' in coll.tasks # not 'implicit_name'
def nested_path(self): collection = Collection.from_module(load("tree")) docs = collection.collections["build"].collections["docs"] assert collection.subcollection_from_path("build.docs") is docs