Repository: numpy/numpy

Issue:
BUG or DOC: np.array dtype can be used to downcast data
In the process of investigating the behaviour of `can_cast` for #13636 , I noticed that:
```
np.array([1000.], 'i1')
# array([-24], dtype=int8)
```
i.e., casting is done unsafely. Yet the docstring suggests downcasting is not possible:
```
dtype : data-type, optional
    The desired data-type for the array.  If not given, then the type will
    be determined as the minimum type required to hold the objects in the
    sequence.  This argument can only be used to 'upcast' the array.  For
    downcasting, use the .astype(t) method.
```
So, we should either ensure `array` behaves as documented, or document the actual behaviour.


Discussion:
Could I work on this ?
@abhinavsagar - help would be appreciated, though note that we first have to decide whether this is a bug in the code or in the documentation!
My take is that it is likely fairly specific to integers ending up using `__int__` a deprecation may be in order, since at least a warning on coercion would be nice, and this actually happens in some cases (i.e. with the large enough integers it gets overflow errors because they need `object` dtype).

But it will have to be some "safe" which translates to pyfloat -> float16 is OK and value based coercion rules for python ints.
@seberg - just to be clear, do you think the following should continue to work?
```
np.array([np.float64(123456789.)], dtype='f2')
# array([inf], dtype=float16)
```
I ask since this is certainly consistent behavour (unlike the int!), it is still inconsistent with the documentation quoted above.
The following suggests you are right about `__int__` vs `__index__`:
```
class mynumber:
    def __init__(self, i):
        self.i = i
    def __int__(self):
        return 'nonsense'
    def __index__(self):
        return self.i.__index__()
     
m = mynumber(1000.)
np.array(m, dtype='i1')
# TypeError: __int__ returned non-int (type str)
```
I think ideally `np.array` would probably use safe casting for everything except "untyped" input (input without an associated dtype).  That is tricky, if we allow packages to add an association (say `decimal -> dtype(decimal)`). 

In any case, right now the documentation seems simply wrong? With the exception of some large integer values failing the coercion due to overflows, we use unsafe casting I guess:
```
np.array(["1.3"], dtype=np.float64)  # works
```

I would probably like to move to a world where this coercion uses safe rules by default and we possibly add a `casting` kwarg. But, right now I feel the practical thing is probably to change the documentation and move such things off until we have a clear picture of the new dtype system, which I assume is coming.

xref gh-6289, which is similar. And possibly another one (although I close some since they are similar as the general integer overflow problems).

EDIT: And yes, I am OK with making sure that python float -> float16 uses value based logic, although at this time I am not sure how ugly that will be.
@seberg - I agree that things are sufficiently complex that at present it is best to just make sure the documentation reflects reality.

@abhinavsagar - if you're still following along, it looks like we're going for a docstring update.

Resolving patch:
diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py
--- a/numpy/core/_add_newdocs.py
+++ b/numpy/core/_add_newdocs.py
@@ -793,8 +793,7 @@
     dtype : data-type, optional
         The desired data-type for the array.  If not given, then the type will
         be determined as the minimum type required to hold the objects in the
-        sequence.  This argument can only be used to 'upcast' the array.  For
-        downcasting, use the .astype(t) method.
+        sequence.
     copy : bool, optional
         If true (default), then the object is copied.  Otherwise, a copy will
         only be made if __array__ returns a copy, if obj is a nested sequence,


Test patch: