multimethod uses Spec() instead of parse_anonymous_spec()

- simplify logic in multimethod
- remove the requirement of multimethod invocations to walk up the stack.
This commit is contained in:
Todd Gamblin 2018-12-05 10:34:46 -06:00 committed by Greg Becker
parent 88cb11758b
commit 61b859193d
3 changed files with 12 additions and 22 deletions

View File

@ -26,11 +26,11 @@
"""
import functools
from llnl.util.lang import caller_locals, get_calling_module_name
from llnl.util.lang import caller_locals
import spack.architecture
import spack.error
from spack.spec import parse_anonymous_spec
from spack.spec import Spec
class SpecMultiMethod(object):
@ -46,11 +46,6 @@ class SpecMultiMethod(object):
to find one that matches the package's spec. If it finds one
(and only one), it will call that method.
The package author is responsible for ensuring that only one
condition on multi-methods ever evaluates to true. If
multiple methods evaluate to true, this will raise an
exception.
This is intended for use with decorators (see below). The
decorator (see docs below) creates SpecMultiMethods and
registers method versions with them.
@ -76,7 +71,7 @@ def __init__(self, default=None):
functools.update_wrapper(self, default)
def register(self, spec, method):
"""Register a version of a method for a particular sys_type."""
"""Register a version of a method for a particular spec."""
self.method_list.append((spec, method))
if not hasattr(self, '__name__'):
@ -91,6 +86,7 @@ def __get__(self, obj, objtype):
# element in the list. The first registered function
# will be the one 'wrapped'.
wrapped_method = self.method_list[0][1]
# Call functools.wraps manually to get all the attributes
# we need to be disguised as the wrapped_method
func = functools.wraps(wrapped_method)(
@ -178,10 +174,6 @@ def install(self, prefix):
self.setup()
# Do more common install stuff
There must be one (and only one) @when clause that matches the
package's spec. If there is more than one, or if none match,
then the method will raise an exception when it's called.
Note that the default version of decorated methods must
*always* come first. Otherwise it will override all of the
platform-specific versions. There's not much we can do to get
@ -189,11 +181,12 @@ def install(self, prefix):
"""
def __init__(self, spec):
pkg = get_calling_module_name()
if spec is True:
spec = pkg
self.spec = (parse_anonymous_spec(spec, pkg)
if spec is not False else None)
self.spec = Spec()
elif spec is not False:
self.spec = Spec(spec)
else:
self.spec = None
def __call__(self, method):
# Get the first definition of the method in the calling scope

View File

@ -14,7 +14,7 @@
def target_factory(spec_string, target_concrete):
spec = Spec(spec_string) if spec_string else Spec()
print spec, spec_string, "AAAAA"
if target_concrete:
spec._mark_concrete()
substitute_abstract_variants(spec)
@ -27,18 +27,15 @@ def argument_factory(argument_spec, left):
# If it's not anonymous, allow it
right = target_factory(argument_spec, False)
except Exception:
print "HAHA"
right = parse_anonymous_spec(argument_spec, left.name)
return right
def check_satisfies(target_spec, argument_spec, target_concrete=False):
left = target_factory(target_spec, target_concrete)
right = argument_factory(argument_spec, left)
print left, 'left', left.name
print right, right.name
# Satisfies is one-directional.
assert left.satisfies(right)
if argument_spec:

View File

@ -21,7 +21,7 @@ class Multimethod(MultimethodBase):
url = 'http://www.example.com/example-1.0.tar.gz'
#
# These functions are only valid for versions 1, 2, and 3.
# These functions are only valid for versions 1, 3, and 4.
#
@when('@1.0')
def no_version_2(self):