Bug 1322025 - Make DependsFunction.func less public. r=chmanchester draft
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 25 Jan 2017 16:32:03 +0900
changeset 467001 1db43252c94cf50bbf256e098d587939a4416e7d
parent 467000 f9158bc3711f98a09d6537a73859d56890d7601e
child 467002 ea5f4083f66593ff2a8428fde899861434a4ddff
push id43083
push userbmo:mh+mozilla@glandium.org
push dateFri, 27 Jan 2017 00:32:10 +0000
reviewerschmanchester
bugs1322025
milestone54.0a1
Bug 1322025 - Make DependsFunction.func less public. r=chmanchester We're going to change the function signature for CombinedDependsFunction, so make it visible in the API that the function member is not meant to be used directly. The linter still does, though, because it needs to look in their guts. At the same time, avoid setting DependsFunction names via the function name itself, because in upcoming changes, it will not be modifiable in some cases.
python/mozbuild/mozbuild/configure/__init__.py
python/mozbuild/mozbuild/configure/lint.py
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -46,54 +46,61 @@ class SandboxDependsFunction(object):
     '''Sandbox-visible representation of @depends functions.'''
     def __call__(self, *arg, **kwargs):
         raise ConfigureError('The `%s` function may not be called'
                              % self.__name__)
 
 
 class DependsFunction(object):
     __slots__ = (
-        'func', 'dependencies', 'when', 'sandboxed', 'sandbox', '_result')
+        '_func', '_name', 'dependencies', 'when', 'sandboxed', 'sandbox',
+        '_result')
 
     def __init__(self, sandbox, func, dependencies, when=None):
         assert isinstance(sandbox, ConfigureSandbox)
-        self.func = func
+        assert not inspect.isgeneratorfunction(func)
+        self._func = func
+        self._name = func.__name__
         self.dependencies = dependencies
         self.sandboxed = wraps(func)(SandboxDependsFunction())
         self.sandbox = sandbox
         self.when = when
         sandbox._depends[self.sandboxed] = self
 
         # Only @depends functions with a dependency on '--help' are executed
         # immediately. Everything else is queued for later execution.
         if sandbox._help_option in dependencies:
             sandbox._value_for(self)
         elif not sandbox._help:
             sandbox._execution_queue.append((sandbox._value_for, (self,)))
 
     @property
     def name(self):
-        return self.func.__name__
+        return self._name
+
+    @name.setter
+    def name(self, value):
+        self._name = value
 
     @property
     def sandboxed_dependencies(self):
         return [
             d.sandboxed if isinstance(d, DependsFunction) else d
             for d in self.dependencies
         ]
 
     @memoize
     def result(self, need_help_dependency=False):
         if self.when and not self.sandbox._value_for(self.when,
                                                      need_help_dependency):
             return None
 
         resolved_args = [self.sandbox._value_for(d, need_help_dependency)
                          for d in self.dependencies]
-        return self.func(*resolved_args)
+        return self._func(*resolved_args)
 
     def __repr__(self):
         return '<%s.%s %s(%s)>' % (
             self.__class__.__module__,
             self.__class__.__name__,
             self.name,
             ', '.join(repr(d) for d in self.dependencies),
         )
@@ -103,17 +110,17 @@ class CombinedDependsFunction(DependsFun
     def __init__(self, sandbox, func, dependencies):
         @memoize
         @wraps(func)
         def wrapper(*args):
             return func(args)
 
         flatten_deps = []
         for d in dependencies:
-            if isinstance(d, CombinedDependsFunction) and d.func == wrapper:
+            if isinstance(d, CombinedDependsFunction) and d._func == wrapper:
                 for d2 in d.dependencies:
                     if d2 not in flatten_deps:
                         flatten_deps.append(d2)
             elif d not in flatten_deps:
                 flatten_deps.append(d)
 
         # Automatically add a --help dependency if one of the dependencies
         # depends on it.
@@ -129,21 +136,21 @@ class CombinedDependsFunction(DependsFun
     @memoize
     def result(self, need_help_dependency=False):
         # Ignore --help for the combined result
         deps = self.dependencies
         if deps[0] == self.sandbox._help_option:
             deps = deps[1:]
         resolved_args = [self.sandbox._value_for(d, need_help_dependency)
                          for d in deps]
-        return self.func(*resolved_args)
+        return self._func(*resolved_args)
 
     def __eq__(self, other):
         return (isinstance(other, self.__class__) and
-                self.func == other.func and
+                self._func == other._func and
                 set(self.dependencies) == set(other.dependencies))
 
     def __ne__(self, other):
         return not self == other
 
 class SandboxedGlobal(dict):
     '''Identifiable dict type for use as function global'''
 
@@ -386,17 +393,17 @@ class ConfigureSandbox(dict):
 
         elif (not isinstance(value, SandboxDependsFunction) and
                 value not in self._templates and
                 not (inspect.isclass(value) and issubclass(value, Exception))):
             raise KeyError('Cannot assign `%s` because it is neither a '
                            '@depends nor a @template' % key)
 
         if isinstance(value, SandboxDependsFunction):
-            self._depends[value].func.__name__ = key
+            self._depends[value].name = key
 
         return super(ConfigureSandbox, self).__setitem__(key, value)
 
     def _resolve(self, arg, need_help_dependency=True):
         if isinstance(arg, SandboxDependsFunction):
             return self._value_for_depends(self._depends[arg],
                                            need_help_dependency)
         return arg
@@ -412,17 +419,16 @@ class ConfigureSandbox(dict):
 
         elif isinstance(obj, Option):
             return self._value_for_option(obj)
 
         assert False
 
     @memoize
     def _value_for_depends(self, obj, need_help_dependency=False):
-        assert not inspect.isgeneratorfunction(obj.func)
         return obj.result(need_help_dependency)
 
     @memoize
     def _value_for_option(self, option):
         implied = {}
         for implied_option in self._implied_options[:]:
             if implied_option.name not in (option.name, option.env):
                 continue
--- a/python/mozbuild/mozbuild/configure/lint.py
+++ b/python/mozbuild/mozbuild/configure/lint.py
@@ -35,17 +35,17 @@ class LintSandbox(ConfigureSandbox):
 
         for dep in self._depends.itervalues():
             self._check_dependencies(dep)
 
     def _check_dependencies(self, obj):
         if isinstance(obj, CombinedDependsFunction) or obj in (self._always,
                                                                self._never):
             return
-        func, glob = self.unwrap(obj.func)
+        func, glob = self.unwrap(obj._func)
         loc = '%s:%d' % (func.func_code.co_filename,
                          func.func_code.co_firstlineno)
         func_args = inspect.getargspec(func)
         if func_args.keywords:
             raise ConfigureError(
                 '%s: Keyword arguments are not allowed in @depends functions'
                 % loc
             )
@@ -75,17 +75,17 @@ class LintSandbox(ConfigureSandbox):
 
     def _missing_help_dependency(self, obj):
         if isinstance(obj, CombinedDependsFunction):
             return False
         if isinstance(obj, DependsFunction):
             if (self._help_option in obj.dependencies or
                 obj in (self._always, self._never)):
                 return False
-            func, glob = self.unwrap(obj.func)
+            func, glob = self.unwrap(obj._func)
             # We allow missing --help dependencies for functions that:
             # - don't use @imports
             # - don't have a closure
             # - don't use global variables
             if func in self._imports or func.func_closure:
                 return True
             for op, arg in disassemble_as_iter(func):
                 if op in ('LOAD_GLOBAL', 'STORE_GLOBAL'):