Opened 3 years ago

Last modified 3 years ago

#3505 new undecided

Cases of Interpolate failing to render properly in cases of replacements (-, ~)

Reported by: gracinet Owned by:
Priority: major Milestone: undecided
Version: 0.8.12 Keywords:
Cc:

Description

Sometimes, instead of doing its interpolation with replacements, Interpolate('abc_%(prop:myprop-default)' can output abc_ instead of abc_propvalue or abc_default. I've seen this even with the property having a non empty value.

This is because the _Lookup class (used internally) takes an optional hasKey parameter, does some special actions if is not passed. This parameter is not passed in case of - and ~ replacement directives:

    def _parseColon_minus(self, d, kw, repl):
        return _Lookup(d, kw,
                       default=Interpolate(repl, **self.kwargs),
                       defaultWhenFalse=False,
                       elideNoneAs='')

    def _parseColon_tilde(self, d, kw, repl):
        return _Lookup(d, kw,
                       default=Interpolate(repl, **self.kwargs),
                       defaultWhenFalse=True,
                       elideNoneAs='')

    def _parseColon_plus(self, d, kw, repl):
        return _Lookup(d, kw,
                       hasKey=Interpolate(repl, **self.kwargs),
                       default='',
                       defaultWhenFalse=False,
                       elideNoneAs='')

To detect that hasKey is not passed, _Lookup uses the classical constant-that-is-not-None pattern:

_notHasKey = object()  # Marker object for _Lookup(..., hasKey=...) default


class _Lookup(util.ComparableMixin, object):
    implements(IRenderable)

    compare_attrs = ('value', 'index', 'default', 'defaultWhenFalse', 'hasKey', 'elideNoneAs')

    def __init__(self, value, index, default=None,
                 defaultWhenFalse=True, hasKey=_notHasKey,
                 elideNoneAs=None):
(...)
            if self.defaultWhenFalse:
                rv = yield build.render(value[index])
                if not rv:
                    rv = yield build.render(self.default)
                elif self.hasKey is not _notHasKey:
                    rv = yield build.render(self.hasKey)
            elif self.hasKey is not _notHasKey:
                rv = yield build.render(self.hasKey)
            else:
                rv = yield build.render(value[index])

But sometimes that fails because the constant can change (notably after a if reload)

Seen on 0.8.12 (took me an awful lot of time to grasp it), forgot about it then.

Got it again today on current master (post 0.9.0b7).

Change History (3)

comment:1 Changed 3 years ago by gracinet

The Interpolate result looks actually like this: abc_<object object at 0xf60e2300>. Within a ShellCommand, on 0.8.12 this goes down all the way and is visible in the web interface.

On 0.9, I tracked it down to the Connection instance's remoteStartCommand() and something further yet down the line replaces it with abc_.

On my experimental-future-production instance of 0.9, this occurs systematically, although I don't use a single reload, and I checked that indeed the _notHasKey changed between Interpolate instantiation and evaluation.

comment:2 Changed 3 years ago by gracinet

Should be fixed in master (Nine) by https://github.com/buildbot/buildbot/pull/2075

comment:3 Changed 3 years ago by gracinet

Finally, the investigation showed that the value stored in _Lookup was the one changing, due to a deepcopy of the Interpolate instance (actually a whole BuildFactory)

Remade cleaner PR at https://github.com/buildbot/buildbot/pull/2082

Note: See TracTickets for help on using tickets.