From 63a1b99ca038babe4b3c15ac23c7eec4fd7eaee7 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Sat, 21 Sep 2019 16:40:39 +0200 Subject: [PATCH] BUG: fix != operation (#1132) --- geopandas/array.py | 6 +++++ geopandas/tests/test_array.py | 14 ++++++++++++ geopandas/tests/test_extension_array.py | 30 ++++++++++++------------- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/geopandas/array.py b/geopandas/array.py index 230d79b..d894c9e 100644 --- a/geopandas/array.py +++ b/geopandas/array.py @@ -1029,6 +1029,9 @@ class GeometryArray(ExtensionArray): lvalues = self rvalues = convert_values(other) + if len(lvalues) != len(rvalues): + raise ValueError("Lengths must match to compare") + # If the operator is not defined for the underlying objects, # a TypeError should be raised res = [op(a, b) for (a, b) in zip(lvalues, rvalues)] @@ -1038,3 +1041,6 @@ class GeometryArray(ExtensionArray): def __eq__(self, other): return self._binop(other, operator.eq) + + def __ne__(self, other): + return self._binop(other, operator.ne) diff --git a/geopandas/tests/test_array.py b/geopandas/tests/test_array.py index 63ef0ea..808c9da 100644 --- a/geopandas/tests/test_array.py +++ b/geopandas/tests/test_array.py @@ -625,6 +625,20 @@ def test_getitem(): assert P5.equals(points[1]) +def test_equality_ops(): + with pytest.raises(ValueError): + P[:5] == P[:7] + + a1 = from_shapely([points[1], points[2], points[3]]) + a2 = from_shapely([points[1], points[0], points[3]]) + + res = a1 == a2 + assert res.tolist() == [True, False, True] + + res = a1 != a2 + assert res.tolist() == [False, True, False] + + def test_dir(): assert "contains" in dir(P) assert "data" in dir(P) diff --git a/geopandas/tests/test_extension_array.py b/geopandas/tests/test_extension_array.py index 7519c3c..a0d0280 100644 --- a/geopandas/tests/test_extension_array.py +++ b/geopandas/tests/test_extension_array.py @@ -13,6 +13,8 @@ A set of fixtures are defined to provide data for the tests (the fixtures expected to be available to pytest by the inherited pandas tests). """ +import operator + import numpy as np import pandas as pd from pandas.tests.extension import base as extension_tests @@ -261,7 +263,9 @@ def all_boolean_reductions(request): return request.param -@pytest.fixture(params=["__eq__", "__ne__", "__le__", "__lt__", "__ge__", "__gt__"]) +# only == and != are support for GeometryArray +# @pytest.fixture(params=["__eq__", "__ne__", "__le__", "__lt__", "__ge__", "__gt__"]) +@pytest.fixture(params=["__eq__", "__ne__"]) def all_compare_operators(request): """ Fixture for dunder names for common compare operations @@ -393,31 +397,25 @@ class TestArithmeticOps(extension_tests.BaseArithmeticOpsTests): class TestComparisonOps(extension_tests.BaseComparisonOpsTests): - @not_yet_implemented + def _compare_other(self, s, data, op_name, other): + op = getattr(operator, op_name.strip("_")) + result = op(s, other) + expected = s.combine(other, op) + self.assert_series_equal(result, expected) + + @skip_pandas_below_024 def test_compare_scalar(self, data, all_compare_operators): # noqa op_name = all_compare_operators s = pd.Series(data) - self._compare_other(s, data, op_name, 0) + self._compare_other(s, data, op_name, data[0]) - @not_yet_implemented + @skip_pandas_below_024 def test_compare_array(self, data, all_compare_operators): # noqa op_name = all_compare_operators s = pd.Series(data) other = pd.Series([data[0]] * len(data)) self._compare_other(s, data, op_name, other) - def test_direct_arith_with_series_returns_not_implemented(self, data): - # EAs should return NotImplemented for ops with Series. - # Pandas takes care of unboxing the series and calling the EA's op. - other = pd.Series(data) - if hasattr(data, "__eq__"): - result = data.__eq__(other) - assert result is NotImplemented - else: - raise pytest.skip( - "{} does not implement __eq__".format(data.__class__.__name__) - ) - class TestMethods(extension_tests.BaseMethodsTests): @no_sorting