Repository: numpy/numpy

Issue:
np.asscalar should pass through scalars
**Suggestion**
It would be very convenient if `np.asscalar()` would pass through scalars.  The use-case is to ensure that an argument is a scalar, regardless what is passed in (as long as it behaves as a scalar).

``` python
>>> np.asarray(1.0)
1.0
>>> np.asarray(1j)
1j
```

Presently these fail as the implementation simply looks for the `.item()` method, which scalars do not possess:

`````` python
>>> np.asarray(1.0)
AttributeError                            Traceback (most recent call last)
<ipython-input-13-c6bc08be135e> in <module>()
----> 1 np.asscalar(1.0)

.../python2.7/site-packages/numpy/lib/type_check.pyc in asscalar(a)
    461 
    462     """
--> 463     return a.item()
    464 
    465 #-----------------------------------------------------------------------------

AttributeError: 'float' object has no attribute 'item'```
``````

**Rational**
It is common to use `np.asarray()` to ensure that the argument is an array (in the case that it might be a list etc.).  In an analogous use case, it would be useful to be able to use `np.asscalar()` to ensure that an argument is a scalar (as long as it can be converted to a scalar).

**Workaround**
Convert the argument to an array first.

``` python
np.asscalar(np.asarray(x))
```

**Resolution**
Perhaps code like the following would work:

``` python
def asscalar(a):
    try:
        return a.item()
    except AttributeError, e:
        return np.asarray(a).item()
```



Discussion:

Resolving patch:
diff --git a/numpy/lib/financial.py b/numpy/lib/financial.py
--- a/numpy/lib/financial.py
+++ b/numpy/lib/financial.py
@@ -208,11 +208,11 @@ def pmt(rate, nper, pv, fv=0, when='end'):
     """
     when = _convert_when(when)
     (rate, nper, pv, fv, when) = map(np.asarray, [rate, nper, pv, fv, when])
-    temp = (1+rate)**nper
-    miter = np.broadcast(rate, nper, pv, fv, when)
-    zer = np.zeros(miter.shape)
-    fact = np.where(rate == zer, nper + zer,
-                    (1 + rate*when)*(temp - 1)/rate + zer)
+    temp = (1 + rate)**nper
+    mask = (rate == 0.0)
+    np.copyto(rate, 1.0, where=mask)
+    z = np.zeros(np.broadcast(rate, nper, pv, fv, when).shape)
+    fact = np.where(mask != z, nper + z, (1 + rate*when)*(temp - 1)/rate + z)
     return -(fv + pv*temp) / fact
 
 def nper(rate, pmt, pv, fv=0, when='end'):


Test patch:
diff --git a/numpy/lib/tests/test_financial.py b/numpy/lib/tests/test_financial.py
--- a/numpy/lib/tests/test_financial.py
+++ b/numpy/lib/tests/test_financial.py
@@ -2,7 +2,8 @@
 
 import numpy as np
 from numpy.testing import (
-    run_module_suite, TestCase, assert_, assert_almost_equal
+    run_module_suite, TestCase, assert_, assert_almost_equal,
+    assert_allclose
     )
 
 
@@ -13,35 +14,37 @@ def test_rate(self):
 
     def test_irr(self):
         v = [-150000, 15000, 25000, 35000, 45000, 60000]
-        assert_almost_equal(np.irr(v),
-                            0.0524, 2)
+        assert_almost_equal(np.irr(v), 0.0524, 2)
         v = [-100, 0, 0, 74]
-        assert_almost_equal(np.irr(v),
-                            -0.0955, 2)
+        assert_almost_equal(np.irr(v), -0.0955, 2)
         v = [-100, 39, 59, 55, 20]
-        assert_almost_equal(np.irr(v),
-                            0.28095, 2)
+        assert_almost_equal(np.irr(v), 0.28095, 2)
         v = [-100, 100, 0, -7]
-        assert_almost_equal(np.irr(v),
-                            -0.0833, 2)
+        assert_almost_equal(np.irr(v), -0.0833, 2)
         v = [-100, 100, 0, 7]
-        assert_almost_equal(np.irr(v),
-                            0.06206, 2)
+        assert_almost_equal(np.irr(v), 0.06206, 2)
         v = [-5, 10.5, 1, -8, 1]
-        assert_almost_equal(np.irr(v),
-                            0.0886, 2)
+        assert_almost_equal(np.irr(v), 0.0886, 2)
 
     def test_pv(self):
-        assert_almost_equal(np.pv(0.07, 20, 12000, 0),
-                            -127128.17, 2)
+        assert_almost_equal(np.pv(0.07, 20, 12000, 0), -127128.17, 2)
 
     def test_fv(self):
-        assert_almost_equal(np.fv(0.075, 20, -2000, 0, 0),
-                            86609.36, 2)
+        assert_almost_equal(np.fv(0.075, 20, -2000, 0, 0), 86609.36, 2)
 
     def test_pmt(self):
-        assert_almost_equal(np.pmt(0.08/12, 5*12, 15000),
-                            -304.146, 3)
+        res = np.pmt(0.08/12, 5*12, 15000)
+        tgt = -304.145914
+        assert_allclose(res, tgt)
+        # Test the edge case where rate == 0.0
+        res = np.pmt(0.0, 5*12, 15000)
+        tgt = -250.0
+        assert_allclose(res, tgt)
+        # Test the case where we use broadcast and
+        # the arguments passed in are arrays.
+        res = np.pmt([[0.0, 0.8],[0.3, 0.8]],[12, 3],[2000, 20000])
+        tgt = np.array([[-166.66667, -19311.258],[-626.90814, -19311.258]])
+        assert_allclose(res, tgt)
 
     def test_ppmt(self):
         np.round(np.ppmt(0.1/12, 1, 60, 55000), 2) == 710.25