Whole file
testing-cabal/mock
The author described this change as “Fix callargs call comparisons”. It counts as a record because the check below fails on the code as it stood at d5590a43c and passes on 2265b42d5, with nothing else changed between the two runs.
Projecttesting-cabal/mock
Fix saved2011-07-19
Sharing licenceBSD-2-Clause · LICENSE.txt
Change size+1226 −1218
What the code was meant to do, written into the code itself as a save note
Fix callargs call comparisons
The change
| 428 | 428 | """ | |
| 429 | 429 | def __eq__(self, other): | |
| 430 | 430 | if len(self) == 3: | |
| 431 | - | if other[0] != self[0]: | |
| 432 | - | return False | |
| 433 | - | args_kwargs = self[1:] | |
| 434 | - | other_args_kwargs = other[1:] | |
| 435 | - | else: | |
| 436 | - | args_kwargs = tuple(self) | |
| 437 | - | other_args_kwargs = other | |
| 438 | - | ||
| 439 | - | if len(other_args_kwargs) == 0: | |
| 440 | - | other_args, other_kwargs = (), {} | |
| 441 | - | elif len(other_args_kwargs) == 3: | |
| 442 | - | # the first unused argument is the name | |
| 443 | - | _, other_args, other_kwargs = other_args_kwargs | |
| 444 | - | elif len(other_args_kwargs) == 1: | |
| 445 | - | if isinstance(other_args_kwargs[0], tuple): | |
| 446 | - | other_args = other_args_kwargs[0] | |
| 447 | - | other_kwargs = {} | |
| 448 | - | elif isinstance(other_args_kwargs[0], basestring): | |
| 449 | - | other_args, other_kwargs = (), {} | |
| 450 | - | else: | |
| 451 | - | other_args = () | |
| 452 | - | other_kwargs = other_args_kwargs[0] | |
| 453 | - | else: | |
| 454 | - | # len 2 | |
| 455 | - | # could be (name, args) or (name, kwargs) or (args, kwargs) | |
| 456 | - | first, second = other_args_kwargs | |
| 457 | - | if isinstance(first, basestring): | |
| 458 | - | if isinstance(second, tuple): | |
| 459 | - | other_args, other_kwargs = second, {} | |
| 460 | - | else: | |
| 461 | - | other_args, other_kwargs = (), second | |
| 462 | - | else: | |
| 463 | - | other_args, other_kwargs = first, second | |
| 464 | - | ||
| 465 | - | return tuple(args_kwargs) == (other_args, other_kwargs) | |
| 466 | - | ||
| 467 | - | ||
| 468 | - | ||
| 469 | - | class Base(object): | |
| 470 | - | _mock_return_value = DEFAULT | |
| 471 | - | _mock_side_effect = None | |
| 472 | - | def __init__(self, *args, **kwargs): | |
| 473 | - | pass | |
| 474 | - | ||
| 475 | - | ||
| 476 | - | ||
| 477 | - | class NonCallableMock(Base): | |
| 478 | - | """ | |
| 479 | - | Create a new ``Mock`` object. ``Mock`` takes several optional arguments | |
| 480 | - | that specify the behaviour of the Mock object: | |
| 481 | - | ||
| 482 | - | * ``spec``: This can be either a list of strings or an existing object (a | |
| 483 | - | class or instance) that acts as the specification for the mock object. If | |
| 484 | - | you pass in an object then a list of strings is formed by calling dir on | |
| 485 | - | the object (excluding unsupported magic attributes and methods). Accessing | |
| 486 | - | any attribute not in this list will raise an ``AttributeError``. | |
| 487 | - | ||
| 488 | - | If ``spec`` is an object (rather than a list of strings) then | |
| 489 | - | `mock.__class__` returns the class of the spec object. This allows mocks | |
| 490 | - | to pass `isinstance` tests. | |
| 491 | - | ||
| 492 | - | * ``spec_set``: A stricter variant of ``spec``. If used, attempting to *set* | |
| 493 | - | or get an attribute on the mock that isn't on the object passed as | |
| 494 | - | ``spec_set`` will raise an ``AttributeError``. | |
| 495 | - | ||
| 496 | - | * ``side_effect``: A function to be called whenever the Mock is called. See | |
| 497 | - | the :attr:`Mock.side_effect` attribute. Useful for raising exceptions or | |
| 498 | - | dynamically changing return values. The function is called with the same | |
| 499 | - | arguments as the mock, and unless it returns :data:`DEFAULT`, the return | |
| 500 | - | value of this function is used as the return value. | |
| 501 | - | ||
| 502 | - | Alternatively ``side_effect`` can be an exception class or instance. In | |
| 503 | - | this case the exception will be raised when the mock is called. | |
| 504 | - | ||
| 505 | - | * ``return_value``: The value returned when the mock is called. By default | |
| 506 | - | this is a new Mock (created on first access). See the | |
| 507 | - | :attr:`Mock.return_value` attribute. | |
| 508 | - | ||
| 509 | - | * ``wraps``: Item for the mock object to wrap. If ``wraps`` is not None | |
| 510 | - | then calling the Mock will pass the call through to the wrapped object | |
| 511 | - | (returning the real result and ignoring ``return_value``). Attribute | |
| 512 | - | access on the mock will return a Mock object that wraps the corresponding | |
| 513 | - | attribute of the wrapped object (so attempting to access an attribute that | |
| 514 | - | doesn't exist will raise an ``AttributeError``). | |
| 515 | - | ||
| 516 | - | If the mock has an explicit ``return_value`` set then calls are not passed | |
| 517 | - | to the wrapped object and the ``return_value`` is returned instead. | |
| 518 | - | ||
| 519 | - | * ``name``: If the mock has a name then it will be used in the repr of the | |
| 520 | - | mock. This can be useful for debugging. The name is propagated to child | |
| 521 | - | mocks. | |
| 522 | - | """ | |
| 523 | - | ||
| 524 | - | def __new__(cls, *args, **kw): | |
| 525 | - | # every instance has its own class | |
| 526 | - | # so we can create magic methods on the | |
| 527 | - | # class without stomping on other mocks | |
| 528 | - | new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__}) | |
| 529 | - | return object.__new__(new) | |
| 530 | - | ||
| 531 | - | ||
| 532 | - | def __init__( | |
| 533 | - | self, spec=None, wraps=None, name=None, spec_set=None, | |
| 534 | - | parent=None, _spec_state=None, _new_name='', _new_parent=None, | |
| 535 | - | **kwargs | |
| 536 | - | ): | |
| 537 | - | self._mock_parent = parent | |
| 538 | - | self._mock_name = name | |
| 539 | - | self._mock_new_name = _new_name | |
| 540 | - | self._mock_new_parent = _new_parent | |
| 541 | - | ||
| 542 | - | self._spec_state = _spec_state | |
| 543 | - | ||
| 544 | - | _spec_class = None | |
| 545 | - | if spec_set is not None: | |
| 546 | - | spec = spec_set | |
| 547 | - | spec_set = True | |
| 548 | - | ||
| 549 | - | if spec is not None and type(spec) is not list: | |
| 550 | - | if isinstance(spec, ClassTypes): | |
| 551 | - | _spec_class = spec | |
| 552 | - | else: | |
| 553 | - | _spec_class = _get_class(spec) | |
| 554 | - | ||
| 555 | - | spec = dir(spec) | |
| 556 | - | ||
| 557 | - | self._spec_class = _spec_class | |
| 558 | - | self._spec_set = spec_set | |
| 559 | - | self._mock_methods = spec | |
| 560 | - | self._mock_children = {} | |
| 561 | - | self._mock_wraps = wraps | |
| 562 | - | self._mock_signature = None | |
| 563 | - | ||
| 564 | - | self._mock_called = False | |
| 565 | - | self._mock_call_args = None | |
| 566 | - | self._mock_call_count = 0 | |
| 567 | - | self._mock_call_args_list = [] | |
| 568 | - | ||
| 569 | - | self.reset_mock() | |
| 570 | - | self.configure_mock(**kwargs) | |
| 571 | - | ||
| 572 | - | _super(NonCallableMock, self).__init__( | |
| 573 | - | spec, wraps, name, spec_set, parent, | |
| 574 | - | _spec_state, **kwargs | |
| 575 | - | ) | |
| 576 | - | ||
| 577 | - | ||
| 578 | - | def __get_return_value(self): | |
| 579 | - | ret = self._mock_return_value | |
| 580 | - | if self._mock_signature is not None: | |
| 581 | - | ret = self._mock_signature.return_value | |
| 582 | - | ||
| 583 | - | if ret is DEFAULT: | |
| 584 | - | ret = self._get_child_mock( | |
| 585 | - | _new_parent=self, _new_name='()' | |
| 586 | - | ) | |
| 587 | - | self.return_value = ret | |
| 588 | - | return ret | |
| 589 | - | ||
| 590 | - | ||
| 591 | - | def __set_return_value(self, value): | |
| 592 | - | if self._mock_signature is not None: | |
| 593 | - | self._mock_signature.return_value = value | |
| 594 | - | else: | |
| 595 | - | self._mock_return_value = value | |
| 596 | - | ||
| 597 | - | __return_value_doc = "The value to be returned when the mock is called." | |
| 598 | - | return_value = property(__get_return_value, __set_return_value, | |
| 599 | - | __return_value_doc) | |
| 600 | - | ||
| 601 | - | ||
| 602 | - | @property | |
| 603 | - | def __class__(self): | |
| 604 | - | if self._spec_class is None: | |
| 605 | - | return type(self) | |
| 606 | - | return self._spec_class | |
| 607 | - | ||
| 608 | - | called = _mock_signature_property('called') | |
| 609 | - | call_count = _mock_signature_property('call_count') | |
| 610 | - | call_args = _mock_signature_property('call_args') | |
| 611 | - | call_args_list = _mock_signature_property('call_args_list') | |
| 612 | - | side_effect = _mock_signature_property('side_effect') | |
| 613 | - | ||
| 614 | - | ||
| 615 | - | def reset_mock(self): | |
| 616 | - | "Restore the mock object to its initial state." | |
| 617 | - | self.called = False | |
| 618 | - | self.call_args = None | |
| 619 | - | self.call_count = 0 | |
| 620 | - | self.mock_calls = [] | |
| 621 | - | self.call_args_list = [] | |
| 622 | - | self.method_calls = [] | |
| 623 | - | ||
| 624 | - | for child in self._mock_children.values(): | |
| 625 | - | child.reset_mock() | |
| 626 | - | ||
| 627 | - | ret = self._mock_return_value | |
| 628 | - | if _is_instance_mock(ret) and ret is not self: | |
| 629 | - | ret.reset_mock() | |
| 630 | - | ||
| 631 | - | ||
| 632 | - | def configure_mock(self, **kwargs): | |
| 633 | - | """XXX needs docstring""" | |
| 634 | - | for arg, val in sorted(kwargs.items(), | |
| 635 | - | # we sort on the number of dots so that | |
| 636 | - | # attributes are set before we set attributes on | |
| 637 | - | # attributes | |
| 638 | - | key=lambda entry: entry[0].count('.')): | |
| 639 | - | args = arg.split('.') | |
| 640 | - | final = args.pop() | |
| 641 | - | obj = self | |
| 642 | - | for entry in args: | |
| 643 | - | obj = getattr(obj, entry) | |
| 644 | - | setattr(obj, final, val) | |
| 645 | - | ||
| 646 | - | ||
| 647 | - | def __getattr__(self, name): | |
| 648 | - | if name == '_mock_methods': | |
| 649 | - | raise AttributeError(name) | |
| 650 | - | elif self._mock_methods is not None: | |
| 651 | - | if name not in self._mock_methods or name in _all_magics: | |
| 652 | - | raise AttributeError("Mock object has no attribute %r" % name) | |
| 653 | - | elif _is_magic(name): | |
| 654 | - | raise AttributeError(name) | |
| 655 | - | ||
| 656 | - | result = self._mock_children.get(name) | |
| 657 | - | if result is None: | |
| 658 | - | wraps = None | |
| 659 | - | if self._mock_wraps is not None: | |
| 660 | - | # XXXX should we get the attribute without triggering code | |
| 661 | - | # execution? | |
| 662 | - | wraps = getattr(self._mock_wraps, name) | |
| 663 | - | ||
| 664 | - | result = self._get_child_mock( | |
| 665 | - | parent=self, name=name, wraps=wraps, _new_name=name, | |
| 666 | - | _new_parent=self | |
| 667 | - | ) | |
| 668 | - | self._mock_children[name] = result | |
| 669 | - | ||
| 670 | - | elif isinstance(result, _SpecState): | |
| 671 | - | result = create_autospec( | |
| 672 | - | result.spec, result.spec_set, result.instance, | |
| 673 | - | None, result.parent, result.name | |
| 674 | - | ) | |
| 675 | - | self._mock_children[name] = result | |
| 676 | - | ||
| 677 | - | return result | |
| 678 | - | ||
| 679 | - | ||
| 680 | - | def __repr__(self): | |
| 681 | - | if self._mock_name is None and self._spec_class is None: | |
| 682 | - | return object.__repr__(self) | |
| 683 | - | ||
| 684 | - | name_string = '' | |
| 685 | - | spec_string = '' | |
| 686 | - | if self._mock_name is not None: | |
| 687 | - | def get_name(name): | |
| 688 | - | if name is None: | |
| 689 | - | return 'mock' | |
| 690 | - | return name | |
| 691 | - | parent = self._mock_parent | |
| 692 | - | name = self._mock_name | |
| 693 | - | while parent is not None: | |
| 694 | - | name = get_name(parent._mock_name) + '.' + name | |
| 695 | - | parent = parent._mock_parent | |
| 696 | - | name_string = ' name=%r' % name | |
| 697 | - | if self._spec_class is not None: | |
| 698 | - | spec_string = ' spec=%r' | |
| 699 | - | if self._spec_set: | |
| 700 | - | spec_string = ' spec_set=%r' | |
| 701 | - | spec_string = spec_string % self._spec_class.__name__ | |
| 702 | - | return "<%s%s%s id='%s'>" % (type(self).__name__, | |
| 703 | - | name_string, | |
| 704 | - | spec_string, | |
| 705 | - | id(self)) | |
| 706 | - | ||
| 707 | - | ||
| 708 | - | def __dir__(self): | |
| 709 | - | extras = self._mock_methods or [] | |
| 710 | - | from_type = dir(type(self)) | |
| 711 | - | from_dict = list(self.__dict__) | |
| 712 | - | ||
| 713 | - | if FILTER_DIR: | |
| 714 | - | from_type = [e for e in from_type if not e.startswith('_')] | |
| 715 | - | from_dict = [e for e in from_dict if not e.startswith('_') or | |
| 716 | - | _is_magic(e)] | |
| 717 | - | return sorted(set(extras + from_type + from_dict + | |
| 718 | - | list(self._mock_children))) | |
| 719 | - | ||
| 720 | - | ||
| 721 | - | def __setattr__(self, name, value): | |
| 722 | - | if not 'method_calls' in self.__dict__: | |
| 723 | - | # allow all attribute setting until initialisation is complete | |
| 724 | - | return object.__setattr__(self, name, value) | |
| 725 | - | ||
| 726 | - | if (self._spec_set and self._mock_methods is not None and name not in | |
| 727 | - | self._mock_methods and name not in self.__dict__ and | |
| 728 | - | name not in _allowed_names): | |
| 729 | - | raise AttributeError("Mock object has no attribute '%s'" % name) | |
| 730 | - | if name in _unsupported_magics: | |
| 731 | - | msg = 'Attempting to set unsupported magic method %r.' % name | |
| 732 | - | raise AttributeError(msg) | |
| 733 | - | elif name in _all_magics: | |
| 734 | - | if self._mock_methods is not None and name not in self._mock_methods: | |
| 735 | - | raise AttributeError("Mock object has no attribute '%s'" % name) | |
| 736 | - | ||
| 737 | - | if isinstance(value, MagicProxy): | |
| 738 | - | setattr(type(self), name, value) | |
| 739 | - | return | |
| 740 | - | ||
| 741 | - | if not _is_instance_mock(value): | |
| 742 | - | setattr(type(self), name, _get_method(name, value)) | |
| 743 | - | original = value | |
| 744 | - | real = lambda *args, **kw: original(self, *args, **kw) | |
| 745 | - | value = mocksignature(value, real, skipfirst=True) | |
| 746 | - | else: | |
| 747 | - | setattr(type(self), name, value) | |
| 748 | - | return object.__setattr__(self, name, value) | |
| 749 | - | ||
| 750 | - | ||
| 751 | - | def __delattr__(self, name): | |
| 752 | - | if name in _all_magics and name in type(self).__dict__: | |
| 753 | - | delattr(type(self), name) | |
| 754 | - | return object.__delattr__(self, name) | |
| 755 | - | ||
| 756 | - | ||
| 757 | - | def _format_mock_call_signature(self, args, kwargs): | |
| 758 | - | name = self._mock_name or 'mock' | |
| 759 | - | message = '%s(%%s)' % name | |
| 760 | - | formatted_args = '' | |
| 761 | - | args_string = ', '.join([repr(arg) for arg in args]) | |
| 762 | - | kwargs_string = ', '.join([ | |
| 763 | - | '%s=%r' % (key, value) for key, value in kwargs.items() | |
| 764 | - | ]) | |
| 765 | - | if args_string: | |
| 766 | - | formatted_args = args_string | |
| 767 | - | if kwargs_string: | |
| 768 | - | if formatted_args: | |
| 769 | - | formatted_args += ', ' | |
| 770 | - | formatted_args += kwargs_string | |
| 771 | - | ||
| 772 | - | return message % formatted_args | |
| 773 | - | ||
| 774 | - | ||
| 775 | - | def _format_mock_failure_message(self, args, kwargs): | |
| 776 | - | message = 'Expected call: %s\nActual call: %s' | |
| 777 | - | expected_string = self._format_mock_call_signature(args, kwargs) | |
| 778 | - | actual_string = self._format_mock_call_signature(*self.call_args) | |
| 779 | - | return message % (expected_string, actual_string) | |
| 780 | - | ||
| 781 | - | ||
| 782 | - | def assert_called_with(_mock_self, *args, **kwargs): | |
| 783 | - | """ | |
| 784 | - | assert that the mock was called with the specified arguments. | |
| 785 | - | ||
| 786 | - | Raises an AssertionError if the args and keyword args passed in are | |
| 787 | - | different to the last call to the mock. | |
| 788 | - | """ | |
| 789 | - | self = _mock_self | |
| 790 | - | if self.call_args is None: | |
| 791 | - | expected = self._format_mock_call_signature(args, kwargs) | |
| 792 | - | raise AssertionError('Expected call: %s\nNot called' % (expected,)) | |
| 793 | - | ||
| 794 | - | if self.call_args != (args, kwargs): | |
| 795 | - | msg = self._format_mock_failure_message(args, kwargs) | |
| 796 | - | raise AssertionError(msg) | |
| 797 | - | ||
| 798 | - | ||
| 799 | - | def assert_called_once_with(_mock_self, *args, **kwargs): | |
| 800 | - | """ | |
| 801 | - | assert that the mock was called exactly once and with the specified | |
| 802 | - | arguments. | |
| 803 | - | """ | |
| 804 | - | self = _mock_self | |
| 805 | - | if not self.call_count == 1: | |
| 806 | - | msg = ("Expected to be called once. Called %s times." % | |
| 807 | - | self.call_count) | |
| 808 | - | raise AssertionError(msg) | |
| 809 | - | return self.assert_called_with(*args, **kwargs) | |
| 810 | - | ||
| 811 | - | ||
| 812 | - | def _get_child_mock(self, **kw): | |
| 813 | - | _type = type(self) | |
| 814 | - | if not issubclass(_type, CallableMixin): | |
| 815 | - | if issubclass(_type, NonCallableMagicMock): | |
| 816 | - | klass = MagicMock | |
| 817 | - | elif issubclass(_type, NonCallableMock) : | |
| 818 | - | klass = Mock | |
| 819 | - | else: | |
| 820 | - | klass = _type.__mro__[1] | |
| 821 | - | return klass(**kw) | |
| 822 | - | ||
| 823 | - | ||
| 824 | - | ||
| 825 | - | class CallableMixin(Base): | |
| 826 | - | ||
| 827 | - | def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, | |
| 2050 further changed lines not shown | |||
The check that tells the two apart
fail→pass·tests/testhelpers.py::CallargsTest::test_callargs_with_args_call_empty_name
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 itd5590a43cda5ffacc53a7a2aa37ba828535ae6c3
Broken version dated2011-07-18
Modulemock
Units changed_Call, callargs
Fingerprint9eba03ca8f9dc304
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
- 2023-04-16_get_signature_object
- 2022-12-28create_autospec
- 2020-01-29_patch_dict
- 2020-01-29_patch_object
- 2012-01-22_Call
- 2011-07-13Fix bug where a failure to create a nested patch could leave patches undone