# Source code for callee.numbers

```"""
Matchers for numbers.
"""
from __future__ import absolute_import

import fractions
import numbers

from callee._compat import IS_PY3
from callee.base import BaseMatcher

__all__ = [
'Number',
'Complex', 'Real', 'Float', 'Rational', 'Fraction',
'Integral', 'Integer', 'Int', 'Long',
]

class NumericMatcher(BaseMatcher):
"""Matches some number type.
This class shouldn't be used directly.
"""
#: Number class to match.
#: Must be overridden in subclasses.
CLASS = None

def __init__(self):
assert self.CLASS, "must specify number type to match"

def match(self, value):
return isinstance(value, self.CLASS)

def __repr__(self):
return "<%s>" % (self.__class__.__name__,)

[docs]class Number(NumericMatcher):
"""Matches any number
(integer, float, complex, custom number types, etc.).
"""
CLASS = numbers.Number

[docs]class Complex(NumericMatcher):
"""Matches any complex number.

This *includes* all real, rational, and integer numbers as well,
which in Python translates to `float`\ s, fractions, and `int`\ egers.
"""
CLASS = numbers.Complex

# TODO: consider adding a dedicated matcher for the ``complex`` type;
# right now, though, ``IsA(complex)`` and ``Complex() & ~Real()`` are probably
# acceptable workarounds

[docs]class Real(NumericMatcher):
"""Matches any real number.

This includes all rational and integer numbers as well, which in Python
translates to fractions, and `int`\ egers.
"""
CLASS = numbers.Real

[docs]class Float(NumericMatcher):
"""Matches a floating point number."""

CLASS = float

[docs]class Rational(NumericMatcher):
"""Matches a rational number.
This includes all `int`\ eger numbers as well.
"""
CLASS = numbers.Rational

[docs]class Fraction(NumericMatcher):
"""Matches a fraction object."""

CLASS = fractions.Fraction

[docs]class Integral(NumericMatcher):
"""Matches any integer.
This ignores the length of integer's internal representation on Python 2.
"""
CLASS = int if IS_PY3 else (int, long)

[docs]class Integer(NumericMatcher):
"""Matches a regular integer.

On Python 3, there is no distinction between regular and long integer,
making this matcher and :class:`Long` equivalent.

On Python 2, this matches the :class:`int` integers exclusively.
"""
CLASS = int

#: Alias for :class:`Integer`.
Int = Integer

[docs]class Long(NumericMatcher):
"""Matches a long integer.

On Python 3, this is the same as regular integer, making this matcher
and :class:`Integer` equivalent.

On Python 2, this matches the :class:`long` integers exclusively.
"""
CLASS = int if IS_PY3 else long
```