Note that there are some explanatory texts on larger screens.

plurals
  1. POAccess an injected object's containing object?
    text
    copied!<p>Given an object A, which contains a callable object B, is there a way to determine "A" from inside <code>B.__call__()</code>?</p> <p>This is for use in test injection, where A.B is originally a method.</p> <p>The code is something like this:</p> <pre><code># Class to be tested. class Outer(object): def __init__(self, arg): self.arg = arg def func(self, *args, **kwargs): print ('Outer self: %r' % (self,)) # Framework-provided: class Injected(object): def __init__(self): self._replay = False self._calls = [] def replay(self): self._replay = True self._calls.reverse() def __call__(self, *args, **kwargs): if not self._replay: expected = (args[0], args[1:], kwargs) self._calls.append(expected) else: expected_s, expected_a, expected_k = self._calls.pop() ok = True # verify args, similar for expected_k == kwargs ok = reduce(lambda x, comp: x and comp[0](comp[1]), zip(expected_a, args), ok) # what to do for expected_s == self? # ok = ok and expected_s(this) ### &lt;= need "this". ### if not ok: raise Exception('Expectations not matched.') # Inject: setattr(Outer, 'func', Injected()) # Set expectations: # - One object, initialised with "3", must pass "here" as 2nd arg. # - One object, initialised with "4", must pass "whatever" as 1st arg. Outer.func(lambda x: x.arg == 3, lambda x: True, lambda x: x=='here') Outer.func(lambda x: x.arg == 4, lambda x: x=='whatever', lambda x: True) Outer.func.replay() # Invoke other code, which ends up doing: o = Outer(3) p = Outer(5) o.func('something', 'here') p.func('whatever', 'next') # &lt;- This should fail, 5 != 4 </code></pre> <p>The question is: Is there a way (black magic is fine) within <code>Injected.__call__()</code> to access what "self" <em>would have been</em> in non-overwritten <code>Outer.func()</code>, to use as "this" (line marked with "###")?</p> <p>Naturally, the code is a bit more complex (the calls can be configured to be in arbitrary order, return values can be set, etc.), but this is the minimal example I could come up with that demonstrates both the problem and most of the constraints.</p> <p>I cannot inject a function with a default argument instead of <code>Outer.func</code> - that breaks recording (if a function were injected, it'd be an unbound method and require an instance of "Outer" as its first argument, rather than a comparator/validator). </p> <p>Theoretically, I could mock out "Outer" completely for its caller. However, setting up the expectations there would probably be more code, and not reusable elsewhere - any similar case/project would also have to reimplement "Outer" (or its equivalent) as a mock.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload