We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
overlay gives confusing error when passed `GeoSeries`
Should either support or give informative error. Right now gives:

```
In [6]: country_cores = overlay(countries, capital_buffer, how='intersection')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-a69b51de5bcf> in <module>()
----> 1 country_cores = overlay(countries, capital_buffer, how='intersection')

/Users/Nick/github/geopandas/geopandas/tools/overlay.py in overlay(df1, df2, how, use_sindex)
     85     # Collect the interior and exterior rings
     86     rings1 = _extract_rings(df1)
---> 87     rings2 = _extract_rings(df2)
     88     mls1 = MultiLineString(rings1)
     89     mls2 = MultiLineString(rings2)

/Users/Nick/github/geopandas/geopandas/tools/overlay.py in _extract_rings(df)
     31     poly_msg = "overlay only takes GeoDataFrames with (multi)polygon geometries"
     32     rings = []
---> 33     for i, feat in df.iterrows():
     34         geom = feat.geometry
     35 

/Users/Nick/github/pandas/pandas/core/generic.py in __getattr__(self, name)
   2665             if name in self._info_axis:
   2666                 return self[name]
-> 2667             return object.__getattribute__(self, name)
   2668 
   2669     def __setattr__(self, name, value):

AttributeError: 'GeoSeries' object has no attribute 'iterrows'
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `geopandas/tools/overlay.py`
Content:
```
1 from shapely.ops import unary_union, polygonize
2 from shapely.geometry import MultiLineString
3 import pandas as pd
4 from geopandas import GeoDataFrame, GeoSeries
5 
6 
7 def _uniquify(columns):
8     ucols = []
9     for col in columns:
10         inc = 1
11         newcol = col
12         while newcol in ucols:
13             inc += 1
14             newcol = "{0}_{1}".format(col, inc)
15         ucols.append(newcol)
16     return ucols
17 
18 
19 def _extract_rings(df):
20     """Collects all inner and outer linear rings from a GeoDataFrame 
21     with (multi)Polygon geometeries
22 
23     Parameters
24     ----------
25     df: GeoDataFrame with MultiPolygon or Polygon geometry column
26 
27     Returns
28     -------
29     rings: list of LinearRings
30     """
31     poly_msg = "overlay only takes GeoDataFrames with (multi)polygon geometries"
32     rings = []
33     for i, feat in df.iterrows():
34         geom = feat.geometry
35 
36         if geom.type not in ['Polygon', 'MultiPolygon']:
37             raise TypeError(poly_msg)
38 
39         if hasattr(geom, 'geoms'):
40             for poly in geom.geoms:  # if it's a multipolygon
41                 if not poly.is_valid:
42                     # geom from layer is not valid attempting fix by buffer 0"
43                     poly = poly.buffer(0)
44                 rings.append(poly.exterior)
45                 rings.extend(poly.interiors)
46         else:
47             if not geom.is_valid:
48                 # geom from layer is not valid attempting fix by buffer 0"
49                 geom = geom.buffer(0)
50             rings.append(geom.exterior)
51             rings.extend(geom.interiors)
52 
53     return rings
54 
55 def overlay(df1, df2, how, use_sindex=True):
56     """Perform spatial overlay between two polygons
57     Currently only supports data GeoDataFrames with polygons
58 
59     Implements several methods (see `allowed_hows` list) that are
60     all effectively subsets of the union.
61 
62     Parameters
63     ----------
64     df1 : GeoDataFrame with MultiPolygon or Polygon geometry column
65     df2 : GeoDataFrame with MultiPolygon or Polygon geometry column
66     how : method of spatial overlay
67     use_sindex : Boolean; Use the spatial index to speed up operation. Default is True.
68 
69     Returns
70     -------
71     df : GeoDataFrame with new set of polygons and attributes resulting from the overlay
72     """
73     allowed_hows = [
74         'intersection',
75         'union',
76         'identity',
77         'symmetric_difference',
78         'difference',  # aka erase
79     ]
80 
81     if how not in allowed_hows:
82         raise ValueError("`how` was \"%s\" but is expected to be in %s" % \
83             (how, allowed_hows))
84 
85     # Collect the interior and exterior rings
86     rings1 = _extract_rings(df1)
87     rings2 = _extract_rings(df2)
88     mls1 = MultiLineString(rings1)
89     mls2 = MultiLineString(rings2)
90 
91     # Union and polygonize
92     try:
93         # calculating union (try the fast unary_union)
94         mm = unary_union([mls1, mls2])
95     except:
96         # unary_union FAILED
97         # see https://github.com/Toblerity/Shapely/issues/47#issuecomment-18506767
98         # calculating union again (using the slow a.union(b))
99         mm = mls1.union(mls2)
100     newpolys = polygonize(mm)
101 
102     # determine spatial relationship
103     collection = []
104     for fid, newpoly in enumerate(newpolys):
105         cent = newpoly.representative_point()
106 
107         # Test intersection with original polys
108         # FIXME there should be a higher-level abstraction to search by bounds
109         # and fall back in the case of no index?
110         if use_sindex and df1.sindex is not None:
111             candidates1 = [x.object for x in
112                            df1.sindex.intersection(newpoly.bounds, objects=True)]
113         else:
114             candidates1 = [i for i, x in df1.iterrows()]
115 
116         if use_sindex and df2.sindex is not None:
117             candidates2 = [x.object for x in
118                            df2.sindex.intersection(newpoly.bounds, objects=True)]
119         else:
120             candidates2 = [i for i, x in df2.iterrows()]
121 
122         df1_hit = False
123         df2_hit = False
124         prop1 = None
125         prop2 = None
126         for cand_id in candidates1:
127             cand = df1.ix[cand_id]
128             if cent.intersects(cand.geometry):
129                 df1_hit = True
130                 prop1 = cand
131                 break  # Take the first hit
132         for cand_id in candidates2:
133             cand = df2.ix[cand_id]
134             if cent.intersects(cand.geometry):
135                 df2_hit = True
136                 prop2 = cand
137                 break  # Take the first hit
138 
139         # determine spatial relationship based on type of overlay
140         hit = False
141         if how == "intersection" and (df1_hit and df2_hit):
142             hit = True
143         elif how == "union" and (df1_hit or df2_hit):
144             hit = True
145         elif how == "identity" and df1_hit:
146             hit = True
147         elif how == "symmetric_difference" and not (df1_hit and df2_hit):
148             hit = True
149         elif how == "difference" and (df1_hit and not df2_hit):
150             hit = True
151 
152         if not hit:
153             continue
154 
155         # gather properties
156         if prop1 is None:
157             prop1 = pd.Series(dict.fromkeys(df1.columns, None))
158         if prop2 is None:
159             prop2 = pd.Series(dict.fromkeys(df2.columns, None))
160 
161         # Concat but don't retain the original geometries
162         out_series = pd.concat([prop1.drop(df1._geometry_column_name),
163                                 prop2.drop(df2._geometry_column_name)])
164 
165         out_series.index = _uniquify(out_series.index)
166 
167         # Create a geoseries and add it to the collection
168         out_series['geometry'] = newpoly
169         collection.append(out_series)
170 
171     # Return geodataframe with new indicies
172     return GeoDataFrame(collection, index=range(len(collection)))
173
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/geopandas/tools/overlay.py b/geopandas/tools/overlay.py
--- a/geopandas/tools/overlay.py
+++ b/geopandas/tools/overlay.py
@@ -30,8 +30,10 @@
     """
     poly_msg = "overlay only takes GeoDataFrames with (multi)polygon geometries"
     rings = []
+    geometry_column = df.geometry.name
+
     for i, feat in df.iterrows():
-        geom = feat.geometry
+        geom = feat[geometry_column]
 
         if geom.type not in ['Polygon', 'MultiPolygon']:
             raise TypeError(poly_msg)
@@ -82,6 +84,9 @@
         raise ValueError("`how` was \"%s\" but is expected to be in %s" % \
             (how, allowed_hows))
 
+    if isinstance(df1, GeoSeries) or isinstance(df2, GeoSeries):
+        raise NotImplementedError("overlay currently only implemented for GeoDataFrames")
+
     # Collect the interior and exterior rings
     rings1 = _extract_rings(df1)
     rings2 = _extract_rings(df2)
@@ -125,13 +130,13 @@
         prop2 = None
         for cand_id in candidates1:
             cand = df1.ix[cand_id]
-            if cent.intersects(cand.geometry):
+            if cent.intersects(cand[df1.geometry.name]):
                 df1_hit = True
                 prop1 = cand
                 break  # Take the first hit
         for cand_id in candidates2:
             cand = df2.ix[cand_id]
-            if cent.intersects(cand.geometry):
+            if cent.intersects(cand[df2.geometry.name]):
                 df2_hit = True
                 prop2 = cand
                 break  # Take the first hit

{"golden_diff": "diff --git a/geopandas/tools/overlay.py b/geopandas/tools/overlay.py\n--- a/geopandas/tools/overlay.py\n+++ b/geopandas/tools/overlay.py\n@@ -30,8 +30,10 @@\n     \"\"\"\n     poly_msg = \"overlay only takes GeoDataFrames with (multi)polygon geometries\"\n     rings = []\n+    geometry_column = df.geometry.name\n+\n     for i, feat in df.iterrows():\n-        geom = feat.geometry\n+        geom = feat[geometry_column]\n \n         if geom.type not in ['Polygon', 'MultiPolygon']:\n             raise TypeError(poly_msg)\n@@ -82,6 +84,9 @@\n         raise ValueError(\"`how` was \\\"%s\\\" but is expected to be in %s\" % \\\n             (how, allowed_hows))\n \n+    if isinstance(df1, GeoSeries) or isinstance(df2, GeoSeries):\n+        raise NotImplementedError(\"overlay currently only implemented for GeoDataFrames\")\n+\n     # Collect the interior and exterior rings\n     rings1 = _extract_rings(df1)\n     rings2 = _extract_rings(df2)\n@@ -125,13 +130,13 @@\n         prop2 = None\n         for cand_id in candidates1:\n             cand = df1.ix[cand_id]\n-            if cent.intersects(cand.geometry):\n+            if cent.intersects(cand[df1.geometry.name]):\n                 df1_hit = True\n                 prop1 = cand\n                 break  # Take the first hit\n         for cand_id in candidates2:\n             cand = df2.ix[cand_id]\n-            if cent.intersects(cand.geometry):\n+            if cent.intersects(cand[df2.geometry.name]):\n                 df2_hit = True\n                 prop2 = cand\n                 break  # Take the first hit\n", "issue": "overlay gives confusing error when passed `GeoSeries`\nShould either support or give informative error. Right now gives:\n\n```\nIn [6]: country_cores = overlay(countries, capital_buffer, how='intersection')\n---------------------------------------------------------------------------\nAttributeError                            Traceback (most recent call last)\n<ipython-input-6-a69b51de5bcf> in <module>()\n----> 1 country_cores = overlay(countries, capital_buffer, how='intersection')\n\n/Users/Nick/github/geopandas/geopandas/tools/overlay.py in overlay(df1, df2, how, use_sindex)\n     85     # Collect the interior and exterior rings\n     86     rings1 = _extract_rings(df1)\n---> 87     rings2 = _extract_rings(df2)\n     88     mls1 = MultiLineString(rings1)\n     89     mls2 = MultiLineString(rings2)\n\n/Users/Nick/github/geopandas/geopandas/tools/overlay.py in _extract_rings(df)\n     31     poly_msg = \"overlay only takes GeoDataFrames with (multi)polygon geometries\"\n     32     rings = []\n---> 33     for i, feat in df.iterrows():\n     34         geom = feat.geometry\n     35 \n\n/Users/Nick/github/pandas/pandas/core/generic.py in __getattr__(self, name)\n   2665             if name in self._info_axis:\n   2666                 return self[name]\n-> 2667             return object.__getattribute__(self, name)\n   2668 \n   2669     def __setattr__(self, name, value):\n\nAttributeError: 'GeoSeries' object has no attribute 'iterrows'\n```\n\n", "before_files": [{"content": "from shapely.ops import unary_union, polygonize\nfrom shapely.geometry import MultiLineString\nimport pandas as pd\nfrom geopandas import GeoDataFrame, GeoSeries\n\n\ndef _uniquify(columns):\n    ucols = []\n    for col in columns:\n        inc = 1\n        newcol = col\n        while newcol in ucols:\n            inc += 1\n            newcol = \"{0}_{1}\".format(col, inc)\n        ucols.append(newcol)\n    return ucols\n\n\ndef _extract_rings(df):\n    \"\"\"Collects all inner and outer linear rings from a GeoDataFrame \n    with (multi)Polygon geometeries\n\n    Parameters\n    ----------\n    df: GeoDataFrame with MultiPolygon or Polygon geometry column\n\n    Returns\n    -------\n    rings: list of LinearRings\n    \"\"\"\n    poly_msg = \"overlay only takes GeoDataFrames with (multi)polygon geometries\"\n    rings = []\n    for i, feat in df.iterrows():\n        geom = feat.geometry\n\n        if geom.type not in ['Polygon', 'MultiPolygon']:\n            raise TypeError(poly_msg)\n\n        if hasattr(geom, 'geoms'):\n            for poly in geom.geoms:  # if it's a multipolygon\n                if not poly.is_valid:\n                    # geom from layer is not valid attempting fix by buffer 0\"\n                    poly = poly.buffer(0)\n                rings.append(poly.exterior)\n                rings.extend(poly.interiors)\n        else:\n            if not geom.is_valid:\n                # geom from layer is not valid attempting fix by buffer 0\"\n                geom = geom.buffer(0)\n            rings.append(geom.exterior)\n            rings.extend(geom.interiors)\n\n    return rings\n\ndef overlay(df1, df2, how, use_sindex=True):\n    \"\"\"Perform spatial overlay between two polygons\n    Currently only supports data GeoDataFrames with polygons\n\n    Implements several methods (see `allowed_hows` list) that are\n    all effectively subsets of the union.\n\n    Parameters\n    ----------\n    df1 : GeoDataFrame with MultiPolygon or Polygon geometry column\n    df2 : GeoDataFrame with MultiPolygon or Polygon geometry column\n    how : method of spatial overlay\n    use_sindex : Boolean; Use the spatial index to speed up operation. Default is True.\n\n    Returns\n    -------\n    df : GeoDataFrame with new set of polygons and attributes resulting from the overlay\n    \"\"\"\n    allowed_hows = [\n        'intersection',\n        'union',\n        'identity',\n        'symmetric_difference',\n        'difference',  # aka erase\n    ]\n\n    if how not in allowed_hows:\n        raise ValueError(\"`how` was \\\"%s\\\" but is expected to be in %s\" % \\\n            (how, allowed_hows))\n\n    # Collect the interior and exterior rings\n    rings1 = _extract_rings(df1)\n    rings2 = _extract_rings(df2)\n    mls1 = MultiLineString(rings1)\n    mls2 = MultiLineString(rings2)\n\n    # Union and polygonize\n    try:\n        # calculating union (try the fast unary_union)\n        mm = unary_union([mls1, mls2])\n    except:\n        # unary_union FAILED\n        # see https://github.com/Toblerity/Shapely/issues/47#issuecomment-18506767\n        # calculating union again (using the slow a.union(b))\n        mm = mls1.union(mls2)\n    newpolys = polygonize(mm)\n\n    # determine spatial relationship\n    collection = []\n    for fid, newpoly in enumerate(newpolys):\n        cent = newpoly.representative_point()\n\n        # Test intersection with original polys\n        # FIXME there should be a higher-level abstraction to search by bounds\n        # and fall back in the case of no index?\n        if use_sindex and df1.sindex is not None:\n            candidates1 = [x.object for x in\n                           df1.sindex.intersection(newpoly.bounds, objects=True)]\n        else:\n            candidates1 = [i for i, x in df1.iterrows()]\n\n        if use_sindex and df2.sindex is not None:\n            candidates2 = [x.object for x in\n                           df2.sindex.intersection(newpoly.bounds, objects=True)]\n        else:\n            candidates2 = [i for i, x in df2.iterrows()]\n\n        df1_hit = False\n        df2_hit = False\n        prop1 = None\n        prop2 = None\n        for cand_id in candidates1:\n            cand = df1.ix[cand_id]\n            if cent.intersects(cand.geometry):\n                df1_hit = True\n                prop1 = cand\n                break  # Take the first hit\n        for cand_id in candidates2:\n            cand = df2.ix[cand_id]\n            if cent.intersects(cand.geometry):\n                df2_hit = True\n                prop2 = cand\n                break  # Take the first hit\n\n        # determine spatial relationship based on type of overlay\n        hit = False\n        if how == \"intersection\" and (df1_hit and df2_hit):\n            hit = True\n        elif how == \"union\" and (df1_hit or df2_hit):\n            hit = True\n        elif how == \"identity\" and df1_hit:\n            hit = True\n        elif how == \"symmetric_difference\" and not (df1_hit and df2_hit):\n            hit = True\n        elif how == \"difference\" and (df1_hit and not df2_hit):\n            hit = True\n\n        if not hit:\n            continue\n\n        # gather properties\n        if prop1 is None:\n            prop1 = pd.Series(dict.fromkeys(df1.columns, None))\n        if prop2 is None:\n            prop2 = pd.Series(dict.fromkeys(df2.columns, None))\n\n        # Concat but don't retain the original geometries\n        out_series = pd.concat([prop1.drop(df1._geometry_column_name),\n                                prop2.drop(df2._geometry_column_name)])\n\n        out_series.index = _uniquify(out_series.index)\n\n        # Create a geoseries and add it to the collection\n        out_series['geometry'] = newpoly\n        collection.append(out_series)\n\n    # Return geodataframe with new indicies\n    return GeoDataFrame(collection, index=range(len(collection)))\n", "path": "geopandas/tools/overlay.py"}], "after_files": [{"content": "from shapely.ops import unary_union, polygonize\nfrom shapely.geometry import MultiLineString\nimport pandas as pd\nfrom geopandas import GeoDataFrame, GeoSeries\n\n\ndef _uniquify(columns):\n    ucols = []\n    for col in columns:\n        inc = 1\n        newcol = col\n        while newcol in ucols:\n            inc += 1\n            newcol = \"{0}_{1}\".format(col, inc)\n        ucols.append(newcol)\n    return ucols\n\n\ndef _extract_rings(df):\n    \"\"\"Collects all inner and outer linear rings from a GeoDataFrame \n    with (multi)Polygon geometeries\n\n    Parameters\n    ----------\n    df: GeoDataFrame with MultiPolygon or Polygon geometry column\n\n    Returns\n    -------\n    rings: list of LinearRings\n    \"\"\"\n    poly_msg = \"overlay only takes GeoDataFrames with (multi)polygon geometries\"\n    rings = []\n    geometry_column = df.geometry.name\n\n    for i, feat in df.iterrows():\n        geom = feat[geometry_column]\n\n        if geom.type not in ['Polygon', 'MultiPolygon']:\n            raise TypeError(poly_msg)\n\n        if hasattr(geom, 'geoms'):\n            for poly in geom.geoms:  # if it's a multipolygon\n                if not poly.is_valid:\n                    # geom from layer is not valid attempting fix by buffer 0\"\n                    poly = poly.buffer(0)\n                rings.append(poly.exterior)\n                rings.extend(poly.interiors)\n        else:\n            if not geom.is_valid:\n                # geom from layer is not valid attempting fix by buffer 0\"\n                geom = geom.buffer(0)\n            rings.append(geom.exterior)\n            rings.extend(geom.interiors)\n\n    return rings\n\ndef overlay(df1, df2, how, use_sindex=True):\n    \"\"\"Perform spatial overlay between two polygons\n    Currently only supports data GeoDataFrames with polygons\n\n    Implements several methods (see `allowed_hows` list) that are\n    all effectively subsets of the union.\n\n    Parameters\n    ----------\n    df1 : GeoDataFrame with MultiPolygon or Polygon geometry column\n    df2 : GeoDataFrame with MultiPolygon or Polygon geometry column\n    how : method of spatial overlay\n    use_sindex : Boolean; Use the spatial index to speed up operation. Default is True.\n\n    Returns\n    -------\n    df : GeoDataFrame with new set of polygons and attributes resulting from the overlay\n    \"\"\"\n    allowed_hows = [\n        'intersection',\n        'union',\n        'identity',\n        'symmetric_difference',\n        'difference',  # aka erase\n    ]\n\n    if how not in allowed_hows:\n        raise ValueError(\"`how` was \\\"%s\\\" but is expected to be in %s\" % \\\n            (how, allowed_hows))\n\n    if isinstance(df1, GeoSeries) or isinstance(df2, GeoSeries):\n        raise NotImplementedError(\"overlay currently only implemented for GeoDataFrames\")\n\n    # Collect the interior and exterior rings\n    rings1 = _extract_rings(df1)\n    rings2 = _extract_rings(df2)\n    mls1 = MultiLineString(rings1)\n    mls2 = MultiLineString(rings2)\n\n    # Union and polygonize\n    try:\n        # calculating union (try the fast unary_union)\n        mm = unary_union([mls1, mls2])\n    except:\n        # unary_union FAILED\n        # see https://github.com/Toblerity/Shapely/issues/47#issuecomment-18506767\n        # calculating union again (using the slow a.union(b))\n        mm = mls1.union(mls2)\n    newpolys = polygonize(mm)\n\n    # determine spatial relationship\n    collection = []\n    for fid, newpoly in enumerate(newpolys):\n        cent = newpoly.representative_point()\n\n        # Test intersection with original polys\n        # FIXME there should be a higher-level abstraction to search by bounds\n        # and fall back in the case of no index?\n        if use_sindex and df1.sindex is not None:\n            candidates1 = [x.object for x in\n                           df1.sindex.intersection(newpoly.bounds, objects=True)]\n        else:\n            candidates1 = [i for i, x in df1.iterrows()]\n\n        if use_sindex and df2.sindex is not None:\n            candidates2 = [x.object for x in\n                           df2.sindex.intersection(newpoly.bounds, objects=True)]\n        else:\n            candidates2 = [i for i, x in df2.iterrows()]\n\n        df1_hit = False\n        df2_hit = False\n        prop1 = None\n        prop2 = None\n        for cand_id in candidates1:\n            cand = df1.ix[cand_id]\n            if cent.intersects(cand[df1.geometry.name]):\n                df1_hit = True\n                prop1 = cand\n                break  # Take the first hit\n        for cand_id in candidates2:\n            cand = df2.ix[cand_id]\n            if cent.intersects(cand[df2.geometry.name]):\n                df2_hit = True\n                prop2 = cand\n                break  # Take the first hit\n\n        # determine spatial relationship based on type of overlay\n        hit = False\n        if how == \"intersection\" and (df1_hit and df2_hit):\n            hit = True\n        elif how == \"union\" and (df1_hit or df2_hit):\n            hit = True\n        elif how == \"identity\" and df1_hit:\n            hit = True\n        elif how == \"symmetric_difference\" and not (df1_hit and df2_hit):\n            hit = True\n        elif how == \"difference\" and (df1_hit and not df2_hit):\n            hit = True\n\n        if not hit:\n            continue\n\n        # gather properties\n        if prop1 is None:\n            prop1 = pd.Series(dict.fromkeys(df1.columns, None))\n        if prop2 is None:\n            prop2 = pd.Series(dict.fromkeys(df2.columns, None))\n\n        # Concat but don't retain the original geometries\n        out_series = pd.concat([prop1.drop(df1._geometry_column_name),\n                                prop2.drop(df2._geometry_column_name)])\n\n        out_series.index = _uniquify(out_series.index)\n\n        # Create a geoseries and add it to the collection\n        out_series['geometry'] = newpoly\n        collection.append(out_series)\n\n    # Return geodataframe with new indicies\n    return GeoDataFrame(collection, index=range(len(collection)))\n", "path": "geopandas/tools/overlay.py"}]}