Repository: pandas-dev/pandas

Issue:
tail throws exception on empty frame
currently, tail throws an exception on an empty frame but head does not.

```
import pandas as pd
df = pd.DataFrame()
df.tail()
```

traceback:
https://gist.github.com/MichaelWS/8256143

Should this be fixed by returning the frame if empty on calls to iloc?  

We can check for empty in tail on length as well or create a new slice with start being None)



Discussion:
actually both of those are wrong

change them to something like 

if n < 0
    n = -n
elif n== 0:
    return self
return self.iloc....(differs for head/tail)

and pls add tests for the missing cases (0 and. 1)

thxs 


Resolving patch:
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -1570,8 +1570,12 @@ def head(self, n=5):
         Returns first n rows
         """
         l = len(self)
-        if abs(n) > l:
-            n = l if n > 0 else -l
+        if l == 0 or n==0:
+            return self
+        if n > l:
+            n = l
+        elif n < -l:
+            n = -l
         return self.iloc[:n]
 
     def tail(self, n=5):
@@ -1579,8 +1583,12 @@ def tail(self, n=5):
         Returns last n rows
         """
         l = len(self)
-        if abs(n) > l:
-            n = l if n > 0 else -l
+        if l == 0 or n == 0:
+            return self
+        if n > l:
+            n = l
+        elif n < -l:
+            n = -l
         return self.iloc[-n:]
 
     #----------------------------------------------------------------------


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -4259,12 +4259,25 @@ def test_repr_column_name_unicode_truncation_bug(self):
     def test_head_tail(self):
         assert_frame_equal(self.frame.head(), self.frame[:5])
         assert_frame_equal(self.frame.tail(), self.frame[-5:])
-
+        assert_frame_equal(self.frame.head(0), self.frame)
+        assert_frame_equal(self.frame.tail(0), self.frame)
+        assert_frame_equal(self.frame.head(-1), self.frame[:-1])
+        assert_frame_equal(self.frame.tail(-1), self.frame[1:])
+        assert_frame_equal(self.frame.head(1), self.frame[:1])
+        assert_frame_equal(self.frame.tail(1), self.frame[-1:])
         # with a float index
         df = self.frame.copy()
         df.index = np.arange(len(self.frame)) + 0.1
         assert_frame_equal(df.head(), df.iloc[:5])
         assert_frame_equal(df.tail(), df.iloc[-5:])
+        assert_frame_equal(df.head(0), df)
+        assert_frame_equal(df.tail(0), df)
+        assert_frame_equal(df.head(-1), df.iloc[:-1])
+        assert_frame_equal(df.tail(-1), df.iloc[1:])
+        #test empty dataframe
+        empty_df = DataFrame()
+        assert_frame_equal(empty_df.tail(), empty_df)
+        assert_frame_equal(empty_df.head(), empty_df)
 
     def test_insert(self):
         df = DataFrame(np.random.randn(5, 3), index=np.arange(5),
diff --git a/pandas/tests/test_generic.py b/pandas/tests/test_generic.py
--- a/pandas/tests/test_generic.py
+++ b/pandas/tests/test_generic.py
@@ -338,7 +338,7 @@ def test_head_tail(self):
             self._compare(o.tail(), o.iloc[-5:])
 
             # 0-len
-            self._compare(o.head(0), o.iloc[:0])
+            self._compare(o.head(0), o.iloc[:])
             self._compare(o.tail(0), o.iloc[0:])
 
             # bounded