AndreaCensi / contracts

PyContracts is a Python package that allows to declare constraints on function parameters and return values. Contracts can be specified using Python3 annotations, or inside a docstring. PyContracts supports a basic type system, variables binding, arithmetic constraints, and has several specialized contracts and an extension API.
http://andreacensi.github.io/contracts/
Other
399 stars 61 forks source link

Can the number contract allow numpy.number? #3

Closed elistevens closed 9 years ago

elistevens commented 12 years ago

Currently, the 'number' contract does not allow instances of numpy.float32 (or numpy.number in general), which surprised me. I think it would be nice to either:

I think that it would be a change to https://github.com/AndreaCensi/contracts/blob/master/src/contracts/library/types_misc.py#L48 :

try:
    import numpy
    number_types = (Number, numpy.number)
except ImportError:
    number_types = Number

add_contract(Keyword('number').setParseAction(CheckType.parse_action(number_types)))

For reference, here is the MRO for numpy.float32:

>>> inspect.getmro(numpy.float32)
(<type 'numpy.float32'>, <type 'numpy.floating'>, <type 'numpy.inexact'>, <type 'numpy.number'>, <type 'numpy.generic'>, <type 'object'>)

Thanks!

AndreaCensi commented 12 years ago

I thought about this, and I guess when one writes "number", one means "whatever I can use as a number". Do you think that wherever you can use a number, you can use a numpy.float32 as well?

Also, given that we are on the topic, do you know other stuff that should be considered a "number" other than numpy structures?

elistevens commented 12 years ago

Sorry for the delay in responding. :)

Yes, numpy.float32 acts very much like a standard python float, except for the number of bits used (I'm sure that there are some differences in behavior, but I haven't found them yet).

decimal.Decimal is also a numbers.Number, and that's the only thing that comes to mind for other numeric types.

Also note that complex is a Number, and while it's probably not worth it to explicitly exclude that from 'number' it's certainly not expected or acceptable for most of the things that I contract to be numbers.

AndreaCensi commented 12 years ago

At this point, I'm inclined to say that number should correspond to all Numbers.Number + np.number, and there should be a "real" that excludes the complex numbers.

However, it seems there is a Numbers.Real but there is no numpy.real...

http://docs.python.org/library/numbers.html http://stackoverflow.com/questions/500328/identifying-numeric-and-array-types-in-numpy

elistevens commented 12 years ago

http://docs.scipy.org/doc/numpy/reference/arrays.scalars.html

Seems like real being numpy.integer and numpy.floating in addition to the standard Python types would work. Though perhaps it would be better to implement it in terms of (numbers.Number|numpy.number),not(complex,numpy.complexfloating) ...? Not sure.

AndreaCensi commented 9 years ago

This was fixed some time ago.