Repository: pandas-dev/pandas

Issue:
Adding new row on TimeDataFrame silently does nothing for integers.
``` python
df = pd.util.testing.makeTimeDataFrame()
df.ix[100,:] = df.ix[0] # does nothing
df.ix[100.0, :] = df.ix[0] # adds a new row
```

Not sure why someone would do such lunacy, but figured I'd report it :P



Discussion:
I believe it's because the second is interpreted as a label instead of a location:

```
df.ix['a', :] = 5
```

@dalejung `ix` very odd fallback behavior; much better off using `iloc/loc`.

and @jtratner is right

@jreback I was more surprised that adding a non datetime didn't error. I wasn't aware of setting with enlargement till just 15 minutes ago. 

fyi. 

``` python
df.loc[100,:] = df.iloc[0]
```

also does nothing. Is that supposed to add a row?

I guess I should only allow enlarge when it is a compatible type...
technically this is allowed (but dumb)

kind of like reindexing, ti will work, but not useful

```
In [10]: df.loc[100.0,:] = df.iloc[0]

In [11]: df
Out[11]: 
                            A         B         C         D
2000-01-03 00:00:00  1.133917 -0.742234  0.253943  0.257431
2000-01-04 00:00:00 -1.170043  0.206878  0.466703 -0.778357
2000-01-05 00:00:00 -0.129783  2.853734  0.424871 -0.426285
2000-01-06 00:00:00 -1.434782  1.763682  0.159602  0.484991
2000-01-07 00:00:00 -0.812384 -1.123200  0.324052  0.897277
2000-01-10 00:00:00 -0.816049  0.317440 -0.424962 -2.754845
2000-01-11 00:00:00 -1.280663  1.318331  0.458699 -0.684365
2000-01-12 00:00:00 -0.594723 -0.096915 -0.438169 -0.399588
2000-01-13 00:00:00 -0.506037 -1.705674 -0.240314  0.857746
2000-01-14 00:00:00 -0.563634  1.096163 -0.742645 -1.881845
2000-01-17 00:00:00  1.249306  0.401445  1.204265 -0.185884
2000-01-18 00:00:00 -2.222697  2.464326  0.825357  0.031255
2000-01-19 00:00:00  1.572763  1.249799 -0.211951 -1.407277
2000-01-20 00:00:00  0.755943  0.359472  0.002930  0.106203
2000-01-21 00:00:00 -0.388139 -1.136465  0.146845  1.542605
2000-01-24 00:00:00 -0.214810  0.610310  1.693897  0.528357
2000-01-25 00:00:00  0.544460  1.674247  0.587789 -1.468309
2000-01-26 00:00:00  1.095833  0.782252 -0.177061 -0.461146
2000-01-27 00:00:00 -0.552260 -1.190525 -0.064258 -0.126099
2000-01-28 00:00:00 -1.653642  0.713682 -0.353627 -0.739781
2000-01-31 00:00:00 -0.036078 -0.007115 -1.788770 -0.058227
2000-02-01 00:00:00  0.508706 -1.133618  0.202209 -0.005820
2000-02-02 00:00:00  1.093139 -0.334661 -0.352597 -0.540348
2000-02-03 00:00:00  0.519011 -0.227214 -0.776306 -0.211545
2000-02-04 00:00:00 -0.315241  0.484756  0.296643 -1.485262
2000-02-07 00:00:00  0.677623 -0.364027  0.791910 -1.001100
2000-02-08 00:00:00  0.294424  1.218632  0.296086  0.265422
2000-02-09 00:00:00 -1.420975  0.952623  0.051837 -1.679938
2000-02-10 00:00:00  0.006552  1.349630 -1.321035 -1.417176
2000-02-11 00:00:00  0.320365 -0.230978 -0.239371 -1.446422
100.0                1.133917 -0.742234  0.253943  0.257431
```


Resolving patch:
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -750,6 +750,13 @@ def _convert_to_indexer(self, obj, axis=0, is_setter=False):
         is_int_index = _is_integer_index(labels)
 
         if com.is_integer(obj) and not is_int_index:
+
+            # if we are setting and its not a valid location
+            # its an insert which fails by definition
+            if is_setter:
+                if obj >= len(self.obj) and not isinstance(labels, MultiIndex):
+                    raise ValueError("cannot set by positional indexing with enlargement")
+
             return obj
 
         try:
@@ -1340,7 +1347,12 @@ def _safe_append_to_index(index, key):
     try:
         return index.insert(len(index), key)
     except:
-        return Index(np.concatenate([index.asobject.values,np.array([key])]))
+
+        # raise here as this is basically an unsafe operation and we want
+        # it to be obvious that you are doing something wrong
+
+        raise ValueError("unsafe appending to index of "
+                         "type {0} with a key {1}".format(index.__class__.__name__,key))
 
 def _maybe_convert_indices(indices, n):
     """ if we have negative indicies, translate to postive here


Test patch:
diff --git a/pandas/sparse/tests/test_sparse.py b/pandas/sparse/tests/test_sparse.py
--- a/pandas/sparse/tests/test_sparse.py
+++ b/pandas/sparse/tests/test_sparse.py
@@ -1078,6 +1078,12 @@ def test_icol(self):
 
     def test_set_value(self):
 
+        # this is invalid because it is not a valid type for this index
+        self.assertRaises(ValueError, self.frame.set_value, 'foobar', 'B', 1.5)
+
+        res = self.frame
+        res.index = res.index.astype(object)
+
         res = self.frame.set_value('foobar', 'B', 1.5)
         self.assert_(res is not self.frame)
         self.assert_(res.index[-1] == 'foobar')
diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py
--- a/pandas/tests/test_indexing.py
+++ b/pandas/tests/test_indexing.py
@@ -1480,6 +1480,30 @@ def test_series_partial_set(self):
         result = ser.iloc[[1,1,0,0]]
         assert_series_equal(result, expected)
 
+    def test_partial_set_invalid(self):
+
+        # GH 4940
+        # allow only setting of 'valid' values
+
+        df = tm.makeTimeDataFrame()
+
+        def f():
+            df.loc[100.0, :] = df.ix[0]
+        self.assertRaises(ValueError, f)
+        def f():
+            df.loc[100,:] = df.ix[0]
+        self.assertRaises(ValueError, f)
+        def f():
+            df.loc['a',:] = df.ix[0]
+        self.assertRaises(ValueError, f)
+
+        def f():
+            df.ix[100.0, :] = df.ix[0]
+        self.assertRaises(ValueError, f)
+        def f():
+            df.ix[100,:] = df.ix[0]
+        self.assertRaises(ValueError, f)
+
     def test_cache_updating(self):
         # GH 4939, make sure to update the cache on setitem