<html><body bgcolor="#FFFFFF"><div>On Jul 29, 2011, at 6:14 PM, Michael Foord &lt;<a href="mailto:michael@voidspace.org.uk">michael@voidspace.org.uk</a>&gt; wrote:<br><br></div><div></div><blockquote type="cite"><div>
    On 29/07/2011 18:37, Tom Davis wrote:
    <blockquote cite="mid:4E32EFEC.9040008@recursivedream.com" type="cite">
      
      On 07/29/2011 01:29 PM, Michael Foord wrote:
      <blockquote cite="mid:4E32EE16.9010509@voidspace.org.uk" type="cite">
        
        On 29/07/2011 18:03, Tom Davis wrote:
        <blockquote cite="mid:4E32E7EA.8090209@recursivedream.com" type="cite">
          
          On 07/29/2011 12:42 PM, Michael Foord wrote:
          <blockquote cite="mid:4E32E2E7.1030804@voidspace.org.uk" type="cite">
            
            On 29/07/2011 17:31, Tom Davis wrote:
            <blockquote cite="mid:4E32E070.3060400@recursivedream.com" type="cite">
              
              Hey all,<br>
              <br>
              I've been using Michael Foord's awesome <i>mock</i>
              package and I've loved it... now I'm running into an
              issue. I'm patching a class, pretty simple:<br>
              <blockquote>from my.module.path import Class<br>
                patch = mock.patch('my.module.path.Class', spec=Class)<br>
                mocked = patch.start()<br>
                mocked.return_value = MyReplacementClass()<br>
              </blockquote>
              I'm doing things this way because I need to mock out a
              class, but provide an alternate implementation that uses
              similar logic to the real class (basically mocking an
              external API by turning it into a memory-mapped API).<br>
              <br>
              Somewhere else, my code gets this mock client and a
              function calls:<br>
              <blockquote>isinstance(client, my.module.path.Class): ...<br>
              </blockquote>
              This call fails with:<br>
              <blockquote>TypeError: isinstance() arg 2 must be a class,
                type, or tuple of classes and type<br>
              </blockquote>
              This was confusing to me, so I did a bit of digging to
              figure out what <i>Class</i> really was, but all was
              well. Here's what I got:<br>
              <blockquote>&lt;MagicMock spec='Class' id='50389456'&gt;<br>
              </blockquote>
            </blockquote>
            <br>
            Well yes - what you have here is a mock *instance* - it
            isn't a class it's a mock of a class. So you can't use this
            as the second argument to isinstance. This is one of the
            problems with type checking (not that it's always wrong -
            just that it causes this kind of difficulty).<br>
            <br>
            Actually it *would* be possible to make a mock object behave
            like a class, by providing __bases__ = (type,) on mock
            instances (or whatever the appropriate bases would be).<br>
          </blockquote>
          First off, thanks for the super fast reply! I'm trying to wrap
          up this project and the intricacies of the final patching
          stage are confusing me a bit. So if I understand this
          correctly, you're saying that isinstance() is actually calling
          (or otherwise obtaining what i set as "return_value") the
          mock? </blockquote>
        <br>
        Not quite, no. <br>
        <br>
        In your test you are replacing "my.module.path.Class" with a
        mock. So when your code tries to use "my.module.path.Class" as
        the second argument to isinstance, it finds the mock. This is
        what your patching has done. You are telling patch to replace
        Class with a mock - so that is what has happened! Unless I have
        misunderstood - but that's what it looks like from both your
        code and description...<br>
        <br>
      </blockquote>
      Quite right! However--and maybe this is where I am confused--I was
      under the impression that providing the "spec" or "spec_set"
      argument to Mock (or in this case, indirectly to Mock via patch())
      allowed it to pass isinstance() tests.<br>
      <br>
    </blockquote><div><br></div>
    Right - a mock created with a spec of Class will pass an isinstance
    check for Class (the first argument to isinstance). That *does not*
    mean that a mock with a spec of Class can be used as the second
    argument.<br></div></blockquote><div><br></div><div>Oh! Well, when you put it like that it just sounds so... obvious ;)</div><br><blockquote type="cite"><div>
    <br>
    <blockquote cite="mid:4E32EFEC.9040008@recursivedream.com" type="cite"> What I *really* want is for calling Class() to return
      a pre-built replacement. I don't want Class itself to be an
      instance of anything, if I can help it. I want it to be a class
      that "looks" just like the original, except for the fact that it
      returns (e.g. via __new__) a custom subclass. I thought patching
      it and providing "return_value" on the patched result would do
      this. But I guess I am creating Mock instances instead? Maybe my
      "mocked" object just needs to be a sublass of Class with __new__
      replaced? Perhaps via the "new" argument to patch()? I will
      continue to investigate.<br></blockquote><div><br></div><div>Well, patching Class.__new__ with a mock that returns a mock with a spec of Class should work.</div></div></blockquote><div><br></div><div>Great, thanks!</div><br><blockquote type="cite"><div><div><br></div><div>Michael</div><div><br></div><br><blockquote cite="mid:4E32EFEC.9040008@recursivedream.com" type="cite">
      <blockquote cite="mid:4E32EE16.9010509@voidspace.org.uk" type="cite"> Michael<br>
        <br>
        <blockquote cite="mid:4E32E7EA.8090209@recursivedream.com" type="cite">The result would make sense, then, though I
          thought it just checked its type? This is a bit above my
          meta-Python experience.<br>
          <blockquote cite="mid:4E32E2E7.1030804@voidspace.org.uk" type="cite"> <br>
            Can you add this as a feature request:<br>
            <br>
            &nbsp;&nbsp;&nbsp; <a moz-do-not-send="true" class="moz-txt-link-freetext" href="https://code.google.com/p/mock/issues/list"><a href="https://code.google.com/p/mock/issues/list">https://code.google.com/p/mock/issues/list</a></a><br>
            <br>
          </blockquote>
          Provided I actually understand what it is (see above), I
          certainly will.<br>
          <br>
          Thanks again!<br>
          <br>
          -Tom<br>
          <blockquote cite="mid:4E32E2E7.1030804@voidspace.org.uk" type="cite"> All the best,<br>
            <br>
            Michael Foord<br>
            <blockquote cite="mid:4E32E070.3060400@recursivedream.com" type="cite">
              <blockquote> </blockquote>
              Seems right to me! Additionally, if I change the instance
              check in the production code to:<br>
              <blockquote>isinstance(client,
                my.module.path.Class._spec_class): ...<br>
              </blockquote>
              It works just fine! I can't do this for obvious reasons,
              but it seems to prove that the MagicMock at least has the
              correct information somewhere, it's just not being
              properly inspected by isinstance().<br>
              <br>
              Any thoughts? I really need this to work.<br>
              <br>
              <fieldset class="mimeAttachmentHeader"></fieldset>
              <br>
              <pre wrap="">_______________________________________________
testing-in-python mailing list
<a moz-do-not-send="true" class="moz-txt-link-abbreviated" href="mailto:testing-in-python@lists.idyll.org"><a href="mailto:testing-in-python@lists.idyll.org">testing-in-python@lists.idyll.org</a></a>
<a moz-do-not-send="true" class="moz-txt-link-freetext" href="http://lists.idyll.org/listinfo/testing-in-python"><a href="http://lists.idyll.org/listinfo/testing-in-python">http://lists.idyll.org/listinfo/testing-in-python</a></a>
</pre>
            </blockquote>
            <br>
            <br>
            <pre class="moz-signature" cols="72">-- 
<a moz-do-not-send="true" class="moz-txt-link-freetext" href="http://www.voidspace.org.uk/"><a href="http://www.voidspace.org.uk/">http://www.voidspace.org.uk/</a></a>

May you do good and not evil
May you find forgiveness for yourself and forgive others
May you share freely, never taking more than you give.
-- the sqlite blessing <a moz-do-not-send="true" class="moz-txt-link-freetext" href="http://www.sqlite.org/different.html"><a href="http://www.sqlite.org/different.html">http://www.sqlite.org/different.html</a></a>
</pre>
          </blockquote>
          <br>
        </blockquote>
        <br>
        <br>
        <pre class="moz-signature" cols="72">-- 
<a moz-do-not-send="true" class="moz-txt-link-freetext" href="http://www.voidspace.org.uk/"><a href="http://www.voidspace.org.uk/">http://www.voidspace.org.uk/</a></a>

May you do good and not evil
May you find forgiveness for yourself and forgive others
May you share freely, never taking more than you give.
-- the sqlite blessing <a moz-do-not-send="true" class="moz-txt-link-freetext" href="http://www.sqlite.org/different.html"><a href="http://www.sqlite.org/different.html">http://www.sqlite.org/different.html</a></a>
</pre>
      </blockquote>
      <br>
    </blockquote>
    <br>
    <br>
    <pre class="moz-signature" cols="72">-- 
<a class="moz-txt-link-freetext" href="http://www.voidspace.org.uk/"><a href="http://www.voidspace.org.uk/">http://www.voidspace.org.uk/</a></a>

May you do good and not evil
May you find forgiveness for yourself and forgive others
May you share freely, never taking more than you give.
-- the sqlite blessing <a class="moz-txt-link-freetext" href="http://www.sqlite.org/different.html"><a href="http://www.sqlite.org/different.html">http://www.sqlite.org/different.html</a></a>
</pre>
  

</div></blockquote></body></html>