Whole file

testing-cabal/mock

The author described this change as Fix for _spec_signature and builtin types. It counts as a record because the check below fails on the code as it stood at 288d23581 and passes on 669d5c84e, with nothing else changed between the two runs.

Fix saved2011-05-17
Sharing licenceBSD-2-Clause · LICENSE.txt
Change size+796 781

What the code was meant to do, written into the code itself as a save note

Fix for _spec_signature and builtin types

The change

359359 self.call_count = 0
360360 self.call_args_list = []
361361 self.method_calls = []
362- for child in self._mock_children.values():
363- child.reset_mock()
364-
365- ret = self._mock_return_value
366- if isinstance(ret, Mock) and ret is not self:
367- ret.reset_mock()
368-
369-
370- def __get_return_value(self):
371- ret = self._mock_return_value
372- if self._mock_signature is not None:
373- ret = self._mock_signature.return_value
374-
375- if ret is DEFAULT:
376- ret = self._get_child_mock()
377- self.return_value = ret
378- return ret
379-
380- def __set_return_value(self, value):
381- if self._mock_signature is not None:
382- self._mock_signature.return_value = value
383- else:
384- self._mock_return_value = value
385-
386- __return_value_doc = "The value to be returned when the mock is called."
387- return_value = property(__get_return_value, __set_return_value,
388- __return_value_doc)
389-
390-
391- def __call__(self, *args, **kwargs):
392- self.called = True
393- self.call_count += 1
394- self.call_args = callargs((args, kwargs))
395- self.call_args_list.append(callargs((args, kwargs)))
396-
397- parent = self._mock_parent
398- name = self._mock_name
399- while parent is not None:
400- parent.method_calls.append(callargs((name, args, kwargs)))
401- if parent._mock_parent is None:
402- break
403- name = parent._mock_name + '.' + name
404- parent = parent._mock_parent
405-
406- ret_val = DEFAULT
407- if self.side_effect is not None:
408- if (isinstance(self.side_effect, BaseException) or
409- isinstance(self.side_effect, ClassTypes) and
410- issubclass(self.side_effect, BaseException)):
411- raise self.side_effect
412-
413- ret_val = self.side_effect(*args, **kwargs)
414- if ret_val is DEFAULT:
415- ret_val = self.return_value
416-
417- if self._mock_wraps is not None and self._mock_return_value is DEFAULT:
418- return self._mock_wraps(*args, **kwargs)
419- if ret_val is DEFAULT:
420- ret_val = self.return_value
421- return ret_val
422-
423-
424- def __getattr__(self, name):
425- if name == '_mock_methods':
426- raise AttributeError(name)
427- elif self._mock_methods is not None:
428- if name not in self._mock_methods or name in _all_magics:
429- raise AttributeError("Mock object has no attribute %r" % name)
430- elif _is_magic(name):
431- raise AttributeError(name)
432-
433- if name not in self._mock_children:
434- wraps = None
435- if self._mock_wraps is not None:
436- # XXXX should we get the attribute without triggering code
437- # execution?
438- wraps = getattr(self._mock_wraps, name)
439- self._mock_children[name] = self._get_child_mock(parent=self,
440- name=name,
441- wraps=wraps)
442-
443- return self._mock_children[name]
444-
445-
446- def __repr__(self):
447- if self._mock_name is None and self._spec_class is None:
448- return object.__repr__(self)
449-
450- name_string = ''
451- spec_string = ''
452- if self._mock_name is not None:
453- def get_name(name):
454- if name is None:
455- return 'mock'
456- return name
457- parent = self._mock_parent
458- name = self._mock_name
459- while parent is not None:
460- name = get_name(parent._mock_name) + '.' + name
461- parent = parent._mock_parent
462- name_string = ' name=%r' % name
463- if self._spec_class is not None:
464- spec_string = ' spec=%r'
465- if self._spec_set:
466- spec_string = ' spec_set=%r'
467- spec_string = spec_string % self._spec_class.__name__
468- return "<%s%s%s id='%s'>" % (type(self).__name__,
469- name_string,
470- spec_string,
471- id(self))
472-
473-
474- def __setattr__(self, name, value):
475- if not 'method_calls' in self.__dict__:
476- # allow all attribute setting until initialisation is complete
477- return object.__setattr__(self, name, value)
478- if (self._spec_set and self._mock_methods is not None and name not in
479- self._mock_methods and name not in self.__dict__ and
480- name != 'return_value'):
481- raise AttributeError("Mock object has no attribute '%s'" % name)
482- if name in _unsupported_magics:
483- msg = 'Attempting to set unsupported magic method %r.' % name
484- raise AttributeError(msg)
485- elif name in _all_magics:
486- if self._mock_methods is not None and name not in self._mock_methods:
487- raise AttributeError("Mock object has no attribute '%s'" % name)
488-
489- if isinstance(value, MagicProxy):
490- setattr(type(self), name, value)
491- return
492-
493- if not isinstance(value, Mock):
494- setattr(type(self), name, _get_method(name, value))
495- original = value
496- real = lambda *args, **kw: original(self, *args, **kw)
497- value = mocksignature(value, real, skipfirst=True)
498- else:
499- setattr(type(self), name, value)
500- return object.__setattr__(self, name, value)
501-
502-
503- def __delattr__(self, name):
504- if name in _all_magics and name in type(self).__dict__:
505- delattr(type(self), name)
506- return object.__delattr__(self, name)
507-
508-
509- def assert_called_with(self, *args, **kwargs):
510- """
511- assert that the mock was called with the specified arguments.
512-
513- Raises an AssertionError if the args and keyword args passed in are
514- different to the last call to the mock.
515- """
516- if self.call_args is None:
517- raise AssertionError('Expected: %s\nNot called' % ((args, kwargs),))
518- if not self.call_args == (args, kwargs):
519- raise AssertionError(
520- 'Expected: %s\nCalled with: %s' % ((args, kwargs), self.call_args)
521- )
522-
523-
524- def assert_called_once_with(self, *args, **kwargs):
525- """
526- assert that the mock was called exactly once and with the specified
527- arguments.
528- """
529- if not self.call_count == 1:
530- msg = ("Expected to be called once. Called %s times." %
531- self.call_count)
532- raise AssertionError(msg)
533- return self.assert_called_with(*args, **kwargs)
534-
535-
536- def _get_child_mock(self, **kw):
537- klass = type(self).__mro__[1]
538- return klass(**kw)
539-
540-
541-
542-class callargs(tuple):
543- """
544- A tuple for holding the results of a call to a mock, either in the form
545- `(args, kwargs)` or `(name, args, kwargs)`.
546-
547- If args or kwargs are empty then a callargs tuple will compare equal to
548- a tuple without those values. This makes comparisons less verbose::
549-
550- callargs('name', (), {}) == ('name',)
551- callargs('name', (1,), {}) == ('name', (1,))
552- callargs((), {'a': 'b'}) == ({'a': 'b'},)
553- """
554- def __eq__(self, other):
555- if len(self) == 3:
556- if other[0] != self[0]:
557- return False
558- args_kwargs = self[1:]
559- other_args_kwargs = other[1:]
560- else:
561- args_kwargs = tuple(self)
562- other_args_kwargs = other
563-
564- if len(other_args_kwargs) == 0:
565- other_args, other_kwargs = (), {}
566- elif len(other_args_kwargs) == 1:
567- if isinstance(other_args_kwargs[0], tuple):
568- other_args = other_args_kwargs[0]
569- other_kwargs = {}
570- else:
571- other_args = ()
572- other_kwargs = other_args_kwargs[0]
573- else:
574- other_args, other_kwargs = other_args_kwargs
575-
576- return tuple(args_kwargs) == (other_args, other_kwargs)
577-
578-
579-def _dot_lookup(thing, comp, import_path):
580- try:
581- return getattr(thing, comp)
582- except AttributeError:
583- __import__(import_path)
584- return getattr(thing, comp)
585-
586-
587-def _importer(target):
588- components = target.split('.')
589- import_path = components.pop(0)
590- thing = __import__(import_path)
591-
592- for comp in components:
593- import_path += ".%s" % comp
594- thing = _dot_lookup(thing, comp, import_path)
595- return thing
596-
597-
598-class _patch(object):
599- def __init__(self, target, attribute, new, spec, create,
600- mocksignature, spec_set):
601- self.target = target
602- self.attribute = attribute
603- self.new = new
604- self.spec = spec
605- self.create = create
606- self.has_local = False
607- self.mocksignature = mocksignature
608- self.spec_set = spec_set
609-
610-
611- def copy(self):
612- return _patch(self.target, self.attribute, self.new, self.spec,
613- self.create, self.mocksignature, self.spec_set)
614-
615-
616- def __call__(self, func):
617- if isinstance(func, ClassTypes):
618- return self.decorate_class(func)
619- return self.decorate_callable(func)
620-
621-
622- def decorate_class(self, klass):
623- for attr in dir(klass):
624- attr_value = getattr(klass, attr)
625- if attr.startswith("test") and hasattr(attr_value, "__call__"):
626- setattr(klass, attr, self.copy()(attr_value))
627- return klass
628-
629-
630- def decorate_callable(self, func):
631- if hasattr(func, 'patchings'):
632- func.patchings.append(self)
633- return func
634-
635- @wraps(func)
636- def patched(*args, **keywargs):
637- # don't use a with here (backwards compatability with 2.5)
638- extra_args = []
639- for patching in patched.patchings:
640- arg = patching.__enter__()
641- if patching.new is DEFAULT:
642- extra_args.append(arg)
643- args += tuple(extra_args)
644- try:
645- return func(*args, **keywargs)
646- finally:
647- for patching in reversed(getattr(patched, 'patchings', [])):
648- patching.__exit__()
649-
650- patched.patchings = [self]
651- if hasattr(func, 'func_code'):
652- # not in Python 3
653- patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno",
654- func.func_code.co_firstlineno)
655- return patched
656-
657-
658- def get_original(self):
659- target = self.target
660- name = self.attribute
661-
662- original = DEFAULT
663- local = False
664-
665- try:
666- original = target.__dict__[name]
667- except (AttributeError, KeyError):
668- original = getattr(target, name, DEFAULT)
669- else:
670- local = True
671-
672- if not self.create and original is DEFAULT:
673- raise AttributeError("%s does not have the attribute %r" % (target, name))
674- return original, local
675-
676-
677- def __enter__(self):
678- """Perform the patch."""
679- new, spec, spec_set = self.new, self.spec, self.spec_set
680- original, local = self.get_original()
681- if new is DEFAULT:
682- # XXXX what if original is DEFAULT - shouldn't use it as a spec
683- inherit = False
684- if spec_set == True:
685- spec_set = original
686- if isinstance(spec_set, ClassTypes):
687- inherit = True
688- elif spec == True:
689- # set spec to the object we are replacing
690- spec = original
691- if isinstance(spec, ClassTypes):
692- inherit = True
693- new = Mock(spec=spec, spec_set=spec_set)
694- if inherit:
695- new.return_value = Mock(spec=spec, spec_set=spec_set)
696- new_attr = new
697- if self.mocksignature:
698- new_attr = mocksignature(original, new)
699-
700- self.temp_original = original
701- self.is_local = local
702- setattr(self.target, self.attribute, new_attr)
703- return new
704-
705-
706- def __exit__(self, *_):
707- """Undo the patch."""
708- if self.is_local and self.temp_original is not DEFAULT:
709- setattr(self.target, self.attribute, self.temp_original)
710- else:
711- delattr(self.target, self.attribute)
712- if not self.create and not hasattr(self.target, self.attribute):
713- # needed for proxy objects like django settings
714- setattr(self.target, self.attribute, self.temp_original)
715-
716- del self.temp_original
717- del self.is_local
718-
719- start = __enter__
720- stop = __exit__
721-
722-
723-def _patch_object(target, attribute, new=DEFAULT, spec=None, create=False,
724- mocksignature=False, spec_set=None):
725- """
726- patch.object(target, attribute, new=DEFAULT, spec=None, create=False,
727- mocksignature=False, spec_set=None)
728-
729- patch the named member (`attribute`) on an object (`target`) with a mock
730- object.
731-
732- Arguments new, spec, create, mocksignature and spec_set have the same
733- meaning as for patch.
734- """
735- return _patch(target, attribute, new, spec, create, mocksignature,
736- spec_set)
737-
738-
739-def patch(target, new=DEFAULT, spec=None, create=False,
740- mocksignature=False, spec_set=None):
741- """
742- ``patch`` acts as a function decorator, class decorator or a context
743- manager. Inside the body of the function or with statement, the ``target``
744- (specified in the form `'PackageName.ModuleName.ClassName'`) is patched
745- with a ``new`` object. When the function/with statement exits the patch is
746- undone.
747-
748- The ``target`` is imported and the specified attribute patched with the new
749- object, so it must be importable from the environment you are calling the
750- decorator from.
751-
752- If ``new`` is omitted, then a new ``Mock`` is created and passed in as an
753- extra argument to the decorated function.
754-
755- The ``spec`` and ``spec_set`` keyword arguments are passed to the ``Mock``
756- if patch is creating one for you.
757-
758- In addition you can pass ``spec=True`` or ``spec_set=True``, which causes
1183 further changed lines not shown

The check that tells the two apart

failpass·tests/testhelpers.py::SpecSignatureTest::test_builtins

Check file tests/testhelpers.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.

Origin and history

The code before it288d23581bcb4596e3d618a2074baa8bc6f2aebd
Broken version dated2011-05-17
Modulemock
Units changedMock, _spec_signature
Fingerprint4edf6ead449771b6
Checked2026-08-18 by goldset/0.1

Every field above is generated by our program. None of it is written by hand.

Other bugs found in testing-cabal/mock