Repository: pandas-dev/pandas

Issue:
Exception when adding a unicode margins_name in pivot_table
#### Code Sample, a copy-pastable example if possible

This throws UnicodeDecodeError in python2

`pd.pivot_table(pd.DataFrame({'foo': [1,2,3]}), index=['foo'], aggfunc=len, margins=True, margins_name=u'Δοκιμή')`
#### Expected Output

Not throwing exception!
#### output of `pd.show_versions()`

<pre>
INSTALLED VERSIONS
------------------
commit: None
python: 2.7.11.final.0
python-bits: 32
OS: Windows
OS-release: 10
machine: AMD64
processor: Intel64 Family 6 Model 58 Stepping 9, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None

pandas: 0.18.1
nose: None
pip: 8.1.2
setuptools: 20.10.1
Cython: None
numpy: 1.11.0
scipy: None
statsmodels: None
xarray: None
IPython: None
sphinx: None
patsy: None
dateutil: 2.5.2
pytz: 2016.4
blosc: None
bottleneck: None
tables: None
numexpr: None
matplotlib: None
openpyxl: None
xlrd: 0.9.4
xlwt: 1.0.0
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
httplib2: None
apiclient: None
sqlalchemy: None
pymysql: None
psycopg2: 2.6.1 (dt dec pq3 ext)
jinja2: None
boto: None
pandas_datareader: None
</pre>


The above is a well-known problem when mixing unicode and non-unicode strings in python2: The fix (for python 2) is very simple, just add a `u` in front of the `exception_msg` string literal in https://github.com/pydata/pandas/blob/master/pandas/tools/pivot.py#L178 i.e line 178 should be `exception_msg = u'Conflicting name "{0}" in margins'.format(margins_name)`

I am not sure what's the correct way to fix that in python 3 and a python2-3 compatible way so I won't provide a PR for that.



Discussion:
mixing of str with unicode is NEVER recommended.

can check the Index if its `inferred_type == 'unicode'` if the passed value is also unicode, otherwise could raise an error. So I'll mark this as a better error message.

@sinhrks I'll start with this one, if it's OK.
I could reproduce the problem. This is the error I'm seeing:

```
(pandas)bash-3.2$ python
Python 2.7.13 (default, Jun  2 2017, 06:36:47)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas as pd
>>> pd.pivot_table(pd.DataFrame({'foo': [1,2,3]}), index=['foo'], aggfunc=len, margins=True, margins_name=u'Δοκιμή')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pandas/core/reshape/pivot.py", line 126, in pivot_table
    margins_name=margins_name, fill_value=fill_value)
  File "pandas/core/reshape/pivot.py", line 148, in _add_margins
    msg = 'Conflicting name "{name}" in margins'.format(name=margins_name)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
```

Resolving patch:
diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py
--- a/pandas/core/reshape/pivot.py
+++ b/pandas/core/reshape/pivot.py
@@ -145,7 +145,7 @@ def _add_margins(table, data, values, rows, cols, aggfunc,
     if not isinstance(margins_name, compat.string_types):
         raise ValueError('margins_name argument must be a string')
 
-    msg = 'Conflicting name "{name}" in margins'.format(name=margins_name)
+    msg = u'Conflicting name "{name}" in margins'.format(name=margins_name)
     for level in table.index.names:
         if margins_name in table.index.get_level_values(level):
             raise ValueError(msg)


Test patch:
diff --git a/pandas/tests/reshape/test_pivot.py b/pandas/tests/reshape/test_pivot.py
--- a/pandas/tests/reshape/test_pivot.py
+++ b/pandas/tests/reshape/test_pivot.py
@@ -1625,3 +1625,13 @@ def test_isleapyear_deprecate(self):
 
         with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
             assert isleapyear(2004)
+
+    def test_pivot_margins_name_unicode(self):
+        # issue #13292
+        greek = u'\u0394\u03bf\u03ba\u03b9\u03bc\u03ae'
+        frame = pd.DataFrame({'foo': [1, 2, 3]})
+        table = pd.pivot_table(frame, index=['foo'], aggfunc=len, margins=True,
+                               margins_name=greek)
+        index = pd.Index([1, 2, 3, greek], dtype='object', name='foo')
+        expected = pd.DataFrame(index=index)
+        tm.assert_frame_equal(table, expected)