diff --git a/doc/source/whatsnew/v0.18.0.txt b/doc/source/whatsnew/v0.18.0.txt index 193d8f83ded79..292444a2bbacc 100644 --- a/doc/source/whatsnew/v0.18.0.txt +++ b/doc/source/whatsnew/v0.18.0.txt @@ -203,6 +203,8 @@ In addition, ``.round()``, ``.floor()`` and ``.ceil()`` will be available thru t .. _whatsnew_0180.api: +- ``pandas.merge()`` and ``DataFrame.merge()`` will show a specific error message when trying to merge with an object that is not of type ``DataFrame`` or a subclass (:issue:`12081`) + .. _whatsnew_0180.api_breaking: Backwards incompatible API changes diff --git a/pandas/tools/merge.py b/pandas/tools/merge.py index 6ea217c4a72a7..60dda9183e7d5 100644 --- a/pandas/tools/merge.py +++ b/pandas/tools/merge.py @@ -184,6 +184,13 @@ def __init__(self, left, right, how='inner', on=None, raise ValueError( 'indicator option can only accept boolean or string arguments') + if not isinstance(left, DataFrame): + raise ValueError( + 'can not merge DataFrame with instance of type {0}'.format(type(left))) + if not isinstance(right, DataFrame): + raise ValueError( + 'can not merge DataFrame with instance of type {0}'.format(type(right))) + # note this function has side effects (self.left_join_keys, self.right_join_keys, diff --git a/pandas/tools/tests/test_merge.py b/pandas/tools/tests/test_merge.py index 9e64e0eeb2792..8be15b212085a 100644 --- a/pandas/tools/tests/test_merge.py +++ b/pandas/tools/tests/test_merge.py @@ -261,6 +261,18 @@ def test_join_on_fails_with_different_column_counts(self): index=tm.makeCustomIndex(10, 2)) merge(df, df2, right_on='a', left_on=['a', 'b']) + + def test_join_on_fails_with_wrong_object_type(self): + # GH12081 + wrongly_typed = [Series([0, 1]), 2, 'str', None, np.ndarray([0, 1])] + df = DataFrame({'a': [1, 1]}) + + for obj in wrongly_typed: + with tm.assertRaisesRegexp(ValueError, str(type(obj))): + merge(obj, df, left_on='a', right_on='a') + with tm.assertRaisesRegexp(ValueError, str(type(obj))): + merge(df, obj, left_on='a', right_on='a') + def test_join_on_pass_vector(self): expected = self.target.join(self.source, on='C') del expected['C']