text: """
  Base classes for argument matchers.
  """
  import inspect
  from operator import itemgetter
  
  from callee._compat import IS_PY3, metaclass
  
  
  __all__ = [
      'Matcher',
      'Eq', 'Is', 'IsNot',
      'Not', 'And', 'Or', 'Either', 'OneOf', 'Xor',
  ]
  
  
  class BaseMatcherMetaclass(type):
      """Metaclass for :class:`BaseMatcher`."""
  
      #: What __magic__ methods of :class:`BaseMatcher`
      #: can be overriden by user-defined subclasses.
      #:
      #: Any method not on this list can only be overridden by classes defined
      #: within this module. This prevents users from accidentally interfering
      #: with fundamental matcher functionality while writing their own matchers.
      #
      #: The names are given without the leading or trailing underscores.
      #:
      USER_OVERRIDABLE_MAGIC_METHODS = ('init', 'repr')
  
      def __new__(meta, classname, bases, dict_):
          """Create a new matcher class."""
          meta._validate_class_definition(classname, bases, dict_)
          return super(BaseMatcherMetaclass, meta) \
              .__new__(meta, classname, bases, dict_)
  
      @classmethod
      def _validate_class_definition(meta, classname, bases, dict_):
          """Ensure the matcher class definition is acceptable.
          :raise RuntimeError: If there is a problem
          """
          # let the BaseMatcher class be created without hassle
          if meta._is_base_matcher_class_definition(classname, dict_):
              return
  
          # ensure that no important magic methods are being overridden
          for name, member in dict_.items():
              if not (name.startswith('__') and name.endswith('__')):
                  continue
  
              # check if it's not a whitelisted magic method name
              name = name[2:-2]
              if not name:
                  continue  # unlikely case of a ``____`` function
              if name not in meta._list_magic_methods(BaseMatcher):
                  continue
              if name in meta.USER_OVERRIDABLE_MAGIC_METHODS:
                  continue
  
              # non-function attributes, like __slots__, are harmless
              if not inspect.isfunction(member):
                  continue
  
              # classes in this very module are exempt, since they define
              # the very behavior of matchers we want to protect
              if member.__module__ == __name__:
                  continue
  
              raise RuntimeError(
                  "matcher class %s cannot override the __%s__ method" % (
                      classname, name))
  
      @classmethod
      def _is_base_matcher_class_definition(meta, classname, dict_):
          """Checks whether given class name and dictionary
          define the :class:`BaseMatcher`.
          """
          if classname != 'BaseMatcher':
              return False
          methods = list(filter(inspect.isfunction, dict_.values()))
          return methods and all(m.__module__ == __name__ for m in methods)
  
      @classmethod
      def _list_magic_methods(meta, class_):
          """Return names of magic methods defined by a class.
          :return: Iterable of magic methods, each w/o the ``__`` prefix/suffix
          """
          return [
              name[2:-2] for name, member in class_.__dict__.items()
              if len(name) > 4 and name.startswith('__') and name.endswith('__')
              and inspect.isfunction(member)
          ]
  
      # TODO: consider making matcher classes interchangeable with matcher
      # objects created w/o ctor args, i.e. making Integer and Integer()
      # equivalent; it'd require this metaclass to implement the magic methods
      # from BaseMatcher and something better than `isinstance(x, BaseMatcher)`
  
  
  @metaclass(BaseMatcherMetaclass)
  class BaseMatcher(object):
      """Base class for all argument matchers.
  
      This class shouldn't be used directly by the clients.
      To create custom matchers, inherit from :class:`Matcher` instead.
      """
      __slots__ = ()
  
      def match(self, value):
          raise NotImplementedError("matching not implemented")
  
      def __repr__(self):
          return "<unspecified matcher>"
  
      def __eq__(self, other):
          if isinstance(other, BaseMatcher):
              raise TypeError(
                  "incorrect use of matcher object as a value to match on")
          return self.match(other)
  
      # TODO: make matcher objects callable
  
      def __invert__(self):
          return Not(self)
  
      def __and__(self, other):
          matchers = other._matchers if isinstance(other, And) else [other]
          return And(self, *matchers)
  
      def __or__(self, other):
          matchers = other._matchers if isinstance(other, Or) else [other]
          return Or(self, *matchers)
  
      def __xor__(self, other):
          matchers = other._matchers if isinstance(other, Either) else [other]
          return Either(self, *matchers)
  
  
  class Matcher(BaseMatcher):
      """Base class for custom (user-defined) argument matchers.
  
      To create a custom matcher, simply inherit from this class
      and implement the :meth:`match` method.
  
      If the matcher is more complicated (e.g. parametrized),
      you may also  want to provide a :meth:`__repr__` method implementation
      for better error messages.
      """
      def __repr__(self):
          """Provides a default ``repr``\ esentation for custom matchers.
  
          This representation will include matcher class name
          and the values of its public attributes.
          If that's insufficient, consider overriding this method.
          """
          args = ""
  
          # check if the matcher class has a parametrized constructor
          has_argful_ctor = False
          if '__init__' in self.__class__.__dict__:
              argnames, vargargs, kwargs, _ = inspect.getargspec(
                  self.__class__.__init__)
              has_argful_ctor = bool(argnames[1:] or vargargs or kwargs)
  
          # if so, then it probably means it has some interesting state
          # in its attributes which we can include in the default representation
          if has_argful_ctor:
              # TODO: __getstate__ instead of __dict__?
              fields = [(name, value) for name, value in self.__dict__.items()
                        if not name.startswith('_')]
              if fields:
                  def repr_value(value):
                      """Safely represent a value as an ASCII string."""
                      if isinstance(value, bytes):
                          value = value.decode('ascii', 'ignore')
                      if not IS_PY3 and isinstance(value, unicode):
                          value = value.encode('ascii', 'replace')
                          value = str(value)
                      return repr(value)
  
                  fields.sort(key=itemgetter(0))
                  args = "(%s)" % ", ".join(
                      "%s=%s" % (name, repr_value(value)[:32])
                      for name, value in fields)
              else:
                  args = "(...)"
  
          return "<%s%s>" % (self.__class__.__name__, args)
  
  
  # Special cases around equality/identity
  
  class Eq(BaseMatcher):
      """Matches a value exactly using the equality (``==``) operator.
  
      This is already the default mode of operation for ``assert_called_with``
      methods on mocks, making this matcher redundant in most situations::
  
          mock_foo.assert_called_with(bar)
          mock_foo.assert_called_with(Eq(bar))  # equivalent
  
      In very rare and specialized cases, however, if the **tested code** treats
      `callee` matcher objects in some special way, using :class:`Eq` may be
      necessary.
  
      Those situations shouldn't generally arise outside of writing tests
      for code that is itself a test library or helper.
      """
      def __init__(self, value):
          """:param value: Value to match against"""
          self.value = value
  
      def match(self, value):
          return self.value == value
  
      def __eq__(self, other):
          return self.match(other)
  
      def __repr__(self):
          # This representation matches the format of comparison operators
          # (such as :class:`Less`) defined in the ``.operators`` module.
          return "<... == %r>" % (self.value,)
  
  
  class Is(BaseMatcher):
      """Matches a value using the identity (``is``) operator."""
  
      def __init__(self, value):
          self.value = value
  
      def match(self, value):
          return value is self.value
  
      def __eq__(self, other):
          return self.match(other)
  
      def __repr__(self):
          # This representation matches the format of comparison operators
          # (such as :class:`Less`) defined in the ``.operators`` module.
          return "<... is %r>" % (self.value,)
  
  
  class IsNot(BaseMatcher):
      """Matches a value using the negated identity (``is not``) operator."""
  
      def __init__(self, value):
          self.value = value
  
      def match(self, value):
          return value is not self.value
  
      def __eq__(self, other):
          return self.match(other)
  
      def __repr__(self):
          # This representation matches the format of comparison operators
          # (such as :class:`Less`) defined in the ``.operators`` module.
          return "<... is not %r>" % (self.value,)
  
  
  # Logical combinators for matchers
  
  class Not(BaseMatcher):
      """Negates given matcher.
  
      :param matcher: Matcher object to negate the semantics of
      """
      def __init__(self, matcher):
          assert isinstance(matcher, BaseMatcher), "Not() expects a matcher"
          self._matcher = matcher
  
      def match(self, value):
          return not self._matcher.match(value)
  
      def __repr__(self):
          return "not %r" % (self._matcher,)
  
      def __invert__(self):
          return self._matcher
  
      def __and__(self, other):
          # convert (~a) & (~b) into ~(a | b) which is one operation less
          # but still equivalent as per de Morgan laws
          if isinstance(other, Not):
              return Not(self.matcher | other.matcher)
          return super(Not, self).__and__(other)
  
      def __or__(self, other):
          # convert (~a) | (~b) into ~(a & b) which is one operation less
          # but still equivalent as per de Morgan laws
          if isinstance(other, Not):
              return Not(self.matcher & other.matcher)
          return super(Not, self).__or__(other)
  
  
  class And(BaseMatcher):
      """Matches the argument only if all given matchers do."""
  
      def __init__(self, *matchers):
          assert matchers, "And() expects at least one matcher"
          assert all(isinstance(m, BaseMatcher)
                     for m in matchers), "And() expects matchers"
          self._matchers = list(matchers)
  
      # TODO: coalesce a & b & c into single And(a, b, c)
  
      def match(self, value):
          return all(matcher.match(value) for matcher in self._matchers)
  
      def __repr__(self):
          return "<%s>" % " and ".join(map(repr, self._matchers))
  
  
  class Or(BaseMatcher):
      """Matches the argument only if at least one given matcher does."""
  
      def __init__(self, *matchers):
          assert matchers, "Or() expects at least one matcher"
          assert all(isinstance(m, BaseMatcher)
                     for m in matchers), "Or() expects matchers"
          self._matchers = list(matchers)
  
      # TODO: coalesce a | b | c into single Or(a, b, c)
  
      def match(self, value):
          return any(matcher.match(value) for matcher in self._matchers)
  
      def __repr__(self):
          return "<%s>" % " or ".join(map(repr, self._matchers))
  
  
  class Either(BaseMatcher):
      """Matches the argument only if some (but not all) of given matchers do.
  
      .. versionadded:: 0.3
      """
      def __init__(self, *matchers):
          assert len(matchers) >= 2, "Either() expects at least two matchers"
          assert all(isinstance(m, BaseMatcher)
                     for m in matchers), "Either() expects matchers"
          self._matchers = list(matchers)
  
      def match(self, value):
          any_matches = bool(self._matchers[0].match(value))
          for matcher in self._matchers[1:]:
              is_match = bool(matcher.match(value))
              if is_match != any_matches:
                  return True
              any_matches |= is_match
          return False
  
      def __repr__(self):
          return "<%s>" % " xor ".join(map(repr, self._matchers))
  
  #: Alias for :class:`Either`.
  OneOf = Either
  #: Alias for :class:`Either`.
  Xor = Either
  