Bug 1363811 - Allow "direct" access to namespace attributes from DependsFunctions. r=cmanchester+432261

To make things simpler in configure code, as well as to allow the linter
to skip bugging about some --help dependencies, we make the following
work:

    something.some_attr

where the result is equivalent to, currently:

    delayed_getattr(something, 'some_attr')
This commit is contained in:
Mike Hommey 2017-05-17 16:09:01 +09:00
Родитель 853aefa3b4
Коммит 59f1035ec6
3 изменённых файлов: 65 добавлений и 1 удалений

Просмотреть файл

@ -47,6 +47,7 @@ class SandboxDependsFunction(object):
def __init__(self, unsandboxed):
self._or = unsandboxed.__or__
self._and = unsandboxed.__and__
self._getattr = unsandboxed.__getattr__
def __call__(self, *arg, **kwargs):
raise ConfigureError('The `%s` function may not be called'
@ -64,6 +65,9 @@ class SandboxDependsFunction(object):
'with another @depends function.')
return self._and(other).sandboxed
def __getattr__(self, key):
return self._getattr(key).sandboxed
def __nonzero__(self):
raise ConfigureError(
'Cannot do boolean operations on @depends functions.')
@ -159,6 +163,19 @@ class DependsFunction(object):
return i
return i
def __getattr__(self, key):
if key.startswith('_'):
return super(DependsFunction, self).__getattr__(key)
# Our function may return None or an object that simply doesn't have
# the wanted key. In that case, just return None.
return TrivialDependsFunction(
self.sandbox, lambda x: getattr(x, key, None), [self], self.when)
class TrivialDependsFunction(DependsFunction):
'''Like a DependsFunction, but the linter won't expect it to have a
dependency on --help ever.'''
class CombinedDependsFunction(DependsFunction):
def __init__(self, sandbox, func, dependencies):

Просмотреть файл

@ -13,6 +13,7 @@ from . import (
ConfigureSandbox,
DependsFunction,
SandboxedGlobal,
TrivialDependsFunction,
)
from .lint_util import disassemble_as_iter
from mozbuild.util import memoize
@ -74,7 +75,7 @@ class LintSandbox(ConfigureSandbox):
)
def _missing_help_dependency(self, obj):
if isinstance(obj, CombinedDependsFunction):
if isinstance(obj, (CombinedDependsFunction, TrivialDependsFunction)):
return False
if isinstance(obj, DependsFunction):
if (self._help_option in obj.dependencies or

Просмотреть файл

@ -1330,6 +1330,52 @@ class TestConfigure(unittest.TestCase):
'FOOandBARandBAZ': foo_value and bar_value and baz_value,
})
def test_depends_getattr(self):
with self.moz_configure('''
@imports(_from='mozbuild.util', _import='ReadOnlyNamespace')
def namespace(**kwargs):
return ReadOnlyNamespace(**kwargs)
option('--foo', nargs=1, help='foo')
@depends('--foo')
def foo(value):
return value
option('--bar', nargs=1, help='bar')
@depends('--bar')
def bar(value):
return value or None
@depends(foo, bar)
def foobar(foo, bar):
return namespace(foo=foo, bar=bar)
set_config('FOO', foobar.foo)
set_config('BAR', foobar.bar)
set_config('BAZ', foobar.baz)
'''):
config = self.get_config()
self.assertEqual(config, {
'FOO': NegativeOptionValue(),
})
config = self.get_config(['--foo=foo'])
self.assertEqual(config, {
'FOO': PositiveOptionValue(('foo',)),
})
config = self.get_config(['--bar=bar'])
self.assertEqual(config, {
'FOO': NegativeOptionValue(),
'BAR': PositiveOptionValue(('bar',)),
})
config = self.get_config(['--foo=foo', '--bar=bar'])
self.assertEqual(config, {
'FOO': PositiveOptionValue(('foo',)),
'BAR': PositiveOptionValue(('bar',)),
})
if __name__ == '__main__':
main()