Repository: pandas-dev/pandas

Issue:
BUG: Joining a DataFrame with a PeriodIndex fails
#### Code Sample
```python
In [19]: dates = pd.period_range('20100101','20100105', freq='D')

In [20]: weights = pd.DataFrame(np.random.randn(5, 5), index=dates, columns = ['g1_%d' % x for x in range(5)])

In [21]: weights.join(pd.DataFrame(np.random.randn(5,5), index=dates, columns = ['g2_%d' % x for x in range(5)]))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-2fdb8b02f5a4> in <module>()
      1 weights.join(
----> 2             pd.DataFrame(np.random.randn(5,5), index=dates, columns = ['g2_%d' % x for x in range(5)]))

/usr/local/lib/python2.7/dist-packages/pandas/core/frame.pyc in join(self, other, on, how, lsuffix, rsuffix, sort)
   4765         # For SparseDataFrame's benefit
   4766         return self._join_compat(other, on=on, how=how, lsuffix=lsuffix,
-> 4767                                  rsuffix=rsuffix, sort=sort)
   4768
   4769     def _join_compat(self, other, on=None, how='left', lsuffix='', rsuffix='',

/usr/local/lib/python2.7/dist-packages/pandas/core/frame.pyc in _join_compat(self, other, on, how, lsuffix, rsuffix, sort)
   4780             return merge(self, other, left_on=on, how=how,
   4781                          left_index=on is None, right_index=True,
-> 4782                          suffixes=(lsuffix, rsuffix), sort=sort)
   4783         else:
   4784             if on is not None:

/usr/local/lib/python2.7/dist-packages/pandas/core/reshape/merge.pyc in merge(left, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator)
     52                          right_index=right_index, sort=sort, suffixes=suffixes,
     53                          copy=copy, indicator=indicator)
---> 54     return op.get_result()
     55
     56

/usr/local/lib/python2.7/dist-packages/pandas/core/reshape/merge.pyc in get_result(self)
    567                 self.left, self.right)
    568
--> 569         join_index, left_indexer, right_indexer = self._get_join_info()
    570
    571         ldata, rdata = self.left._data, self.right._data

/usr/local/lib/python2.7/dist-packages/pandas/core/reshape/merge.pyc in _get_join_info(self)
    720             join_index, left_indexer, right_indexer = \
    721                 left_ax.join(right_ax, how=self.how, return_indexers=True,
--> 722                              sort=self.sort)
    723         elif self.right_index and self.how == 'left':
    724             join_index, left_indexer, right_indexer = \

TypeError: join() got an unexpected keyword argument 'sort'

```

It seems the sort kwarg is invalid, but the internals are passing it in regardless


#### Output of ``pd.show_versions()``

<details>
In [22]: pd.show_versions()
/usr/local/lib/python2.7/dist-packages/xarray/core/formatting.py:16: FutureWarning: The pandas.tslib module is deprecated and will be removed in a future version.
  from pandas.tslib import OutOfBoundsDatetime

INSTALLED VERSIONS
------------------
commit: None
python: 2.7.12.final.0
python-bits: 64
OS: Linux
OS-release: 4.9.13-moby
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: None
LOCALE: None.None

pandas: 0.20.1
pytest: 3.0.7
pip: 9.0.1
setuptools: 35.0.2
Cython: 0.25.2
numpy: 1.12.1
scipy: 0.19.0
xarray: 0.9.2
IPython: 5.3.0
sphinx: None
patsy: 0.4.1
dateutil: 2.6.0
pytz: 2017.2
blosc: None
bottleneck: 1.2.0
tables: None
numexpr: 2.6.2
feather: None
matplotlib: 2.0.1
openpyxl: None
xlrd: None
xlwt: 1.2.0
xlsxwriter: None
lxml: None
bs4: None
html5lib: 0.999999999
sqlalchemy: 1.1.9
pymysql: None
psycopg2: None
jinja2: 2.9.6
s3fs: None
pandas_gbq: 0.1.6
pandas_datareader: None
</details>



Discussion:
this fixes if you can do a PR

```
diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py
index 15fd9b7..50d5958 100644
--- a/pandas/core/indexes/period.py
+++ b/pandas/core/indexes/period.py
@@ -919,14 +919,16 @@ class PeriodIndex(DatelikeOps, DatetimeIndexOpsMixin, Int64Index):
                               self[loc:].asi8))
         return self._shallow_copy(idx)
 
-    def join(self, other, how='left', level=None, return_indexers=False):
+    def join(self, other, how='left', level=None, return_indexers=False,
+             sort=False):
         """
         See Index.join
         """
         self._assert_can_do_setop(other)
 
         result = Int64Index.join(self, other, how=how, level=level,
-                                 return_indexers=return_indexers)
+                                 return_indexers=return_indexers,
+                                 sort=sort)
 
         if return_indexers:
             result, lidx, ridx = result
```

obviously need some more tests on the index join methods as well :>

Here is the tests for datetimes in ``pandas/tests/indexes/datetimes/test_datetimes.py``
need to do something like this in periods/test_period.py
```
    def test_join_self(self):
        index = date_range('1/1/2000', periods=10)
        kinds = 'outer', 'inner', 'left', 'right'
        for kind in kinds:
            joined = index.join(index, how=kind)
            assert index is joined
```
if you can do this in next day or 2 can get into 0.20.2 (end of week)

Resolving patch:
diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py
--- a/pandas/core/indexes/base.py
+++ b/pandas/core/indexes/base.py
@@ -3126,7 +3126,7 @@ def _join_non_unique(self, other, how='left', return_indexers=False):
         left_idx = _ensure_platform_int(left_idx)
         right_idx = _ensure_platform_int(right_idx)
 
-        join_index = self.values.take(left_idx)
+        join_index = np.asarray(self.values.take(left_idx))
         mask = left_idx == -1
         np.putmask(join_index, mask, other._values.take(right_idx))
 
diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py
--- a/pandas/core/indexes/period.py
+++ b/pandas/core/indexes/period.py
@@ -912,14 +912,16 @@ def insert(self, loc, item):
                               self[loc:].asi8))
         return self._shallow_copy(idx)
 
-    def join(self, other, how='left', level=None, return_indexers=False):
+    def join(self, other, how='left', level=None, return_indexers=False,
+             sort=False):
         """
         See Index.join
         """
         self._assert_can_do_setop(other)
 
         result = Int64Index.join(self, other, how=how, level=level,
-                                 return_indexers=return_indexers)
+                                 return_indexers=return_indexers,
+                                 sort=sort)
 
         if return_indexers:
             result, lidx, ridx = result
diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py
--- a/pandas/core/indexes/timedeltas.py
+++ b/pandas/core/indexes/timedeltas.py
@@ -516,7 +516,8 @@ def union(self, other):
                     result.freq = to_offset(result.inferred_freq)
             return result
 
-    def join(self, other, how='left', level=None, return_indexers=False):
+    def join(self, other, how='left', level=None, return_indexers=False,
+             sort=False):
         """
         See Index.join
         """
@@ -527,7 +528,8 @@ def join(self, other, how='left', level=None, return_indexers=False):
                 pass
 
         return Index.join(self, other, how=how, level=level,
-                          return_indexers=return_indexers)
+                          return_indexers=return_indexers,
+                          sort=sort)
 
     def _wrap_joined_index(self, joined, other):
         name = self.name if self.name == other.name else None


Test patch:
diff --git a/pandas/tests/frame/test_join.py b/pandas/tests/frame/test_join.py
--- a/pandas/tests/frame/test_join.py
+++ b/pandas/tests/frame/test_join.py
@@ -3,11 +3,19 @@
 import pytest
 import numpy as np
 
-from pandas import DataFrame, Index
+from pandas import DataFrame, Index, PeriodIndex
 from pandas.tests.frame.common import TestData
 import pandas.util.testing as tm
 
 
+@pytest.fixture
+def frame_with_period_index():
+    return DataFrame(
+        data=np.arange(20).reshape(4, 5),
+        columns=list('abcde'),
+        index=PeriodIndex(start='2000', freq='A', periods=4))
+
+
 @pytest.fixture
 def frame():
     return TestData().frame
@@ -139,3 +147,21 @@ def test_join_overlap(frame):
 
     # column order not necessarily sorted
     tm.assert_frame_equal(joined, expected.loc[:, joined.columns])
+
+
+def test_join_period_index(frame_with_period_index):
+    other = frame_with_period_index.rename(
+        columns=lambda x: '{key}{key}'.format(key=x))
+
+    joined_values = np.concatenate(
+        [frame_with_period_index.values] * 2, axis=1)
+
+    joined_cols = frame_with_period_index.columns.append(other.columns)
+
+    joined = frame_with_period_index.join(other)
+    expected = DataFrame(
+        data=joined_values,
+        columns=joined_cols,
+        index=frame_with_period_index.index)
+
+    tm.assert_frame_equal(joined, expected)
diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py
--- a/pandas/tests/indexes/common.py
+++ b/pandas/tests/indexes/common.py
@@ -905,7 +905,7 @@ def test_fillna(self):
 
     def test_nulls(self):
         # this is really a smoke test for the methods
-        # as these are adequantely tested for function elsewhere
+        # as these are adequately tested for function elsewhere
 
         for name, index in self.indices.items():
             if len(index) == 0:
@@ -933,3 +933,10 @@ def test_empty(self):
         index = self.create_index()
         assert not index.empty
         assert index[:0].empty
+
+    @pytest.mark.parametrize('how', ['outer', 'inner', 'left', 'right'])
+    def test_join_self_unique(self, how):
+        index = self.create_index()
+        if index.is_unique:
+            joined = index.join(index, how=how)
+            assert (index == joined).all()
diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py
--- a/pandas/tests/indexes/period/test_period.py
+++ b/pandas/tests/indexes/period/test_period.py
@@ -773,3 +773,9 @@ def test_map(self):
         result = index.map(lambda x: x.ordinal)
         exp = Index([x.ordinal for x in index])
         tm.assert_index_equal(result, exp)
+
+    @pytest.mark.parametrize('how', ['outer', 'inner', 'left', 'right'])
+    def test_join_self(self, how):
+        index = period_range('1/1/2000', periods=10)
+        joined = index.join(index, how=how)
+        assert index is joined