#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------
# Copyright (c) Merchise Autrement [~º/~] and Contributors
# All rights reserved.
#
# This is free software; you can do what the LICENCE file allows you to.
#
"""The Infinity value.
Not all values are comparable with `Infinity`:obj: by default. The ABC
`InfinityComparable`:class: holds the registry of such values. Any `number
<numbers.Number>`:class: is comparable with `Infinity`:obj:.
`Dates <datetime.date>`:class:, `datetimes <datetime.datetime>`:class: and
`time deltas <datetime.timedelta>`:class: are also registered by default.
.. warning:: In Python 2, dates, datetimes and time deltas must be the right
operand, as in ``Infinity > today``. Doing ``today < Infinity``
fails in Python 2.
"""
import abc
import datetime
from numbers import Number
from functools import total_ordering
[docs]class InfinityComparable(metaclass=abc.ABCMeta):
"""Any type that can be sensibly compared to infinity.
All types in the `number <numbers.Number>`:class: tower are *always*
comparable.
Classes `datetime.date`:class:, `datetime.datetime`:class:, and
`datetime.timedelta`:class: are automatically registered.
"""
@classmethod
def __subclasshook__(self, cls):
if isinstance(cls, type) and issubclass(cls, Number):
return True
else:
return NotImplemented
InfinityComparable.register(datetime.date)
InfinityComparable.register(datetime.datetime)
InfinityComparable.register(datetime.timedelta)
@total_ordering
class InfinityType:
_positive = None
_negative = None
def __getnewargs__(self):
return (self.sign,)
def __new__(cls, sign):
if sign < 0:
res = cls._negative
if not res:
cls._negative = res = object.__new__(cls)
else:
res = cls._positive
if not res:
cls._positive = res = object.__new__(cls)
return res
def __init__(self, sign):
self.sign = -1 if sign < 0 else 1
def __lt__(self, other):
if isinstance(other, InfinityComparable):
return self.sign < 0 # True iff -Infinity
elif isinstance(other, InfinityType):
return self.sign < other.sign
else:
return NotImplemented
def __eq__(self, other):
if isinstance(other, InfinityType):
return self.sign == other.sign
else:
return NotImplemented
def __neg__(self):
return type(self)(-self.sign)
def __str__(self):
return "∞" if self.sign > 0 else "-∞"
def __repr__(self):
return "Infinity" if self.sign > 0 else "-Infinity"
def __hash__(self):
return id(self)
Infinity = InfinityType(+1)