We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AttributeError: 'LineString' object has no attribute 'exterior'
Running the first example from #13 prints this (snipped) traceback:

```
  File ".../matplotlib/transforms.py", line 2227, in transform_path_non_affine
    return self._a.transform_path_non_affine(path)
  File ".../Cartopy-0.12.x-py2.7-linux-x86_64.egg/cartopy/mpl/geoaxes.py", line 169, in transform_path_non_affine
    getattr(self, 'force_path_ccw', False))
  File ".../Cartopy-0.12.x-py2.7-linux-x86_64.egg/cartopy/mpl/patch.py", line 226, in path_to_geos
    if force_ccw and not geom.exterior.is_ccw:
AttributeError: 'LineString' object has no attribute 'exterior'
```

I'm not sure if this can be triggered by other (i.e., not otherwise known to be broken) usage.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/cartopy/mpl/patch.py`
Content:
```
1 # (C) British Crown Copyright 2011 - 2014, Met Office
2 #
3 # This file is part of cartopy.
4 #
5 # cartopy is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU Lesser General Public License as published by the
7 # Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # cartopy is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with cartopy.  If not, see <http://www.gnu.org/licenses/>.
17 """
18 Provides shapely geometry <-> matplotlib path support.
19 
20 
21 See also `Shapely Geometric Objects <see_also_shapely>`_
22 and `Matplotlib Path API <http://matplotlib.org/api/path_api.html>`_.
23 
24 .. see_also_shapely:
25    http://toblerity.github.com/shapely/manual.html#geometric-objects
26 
27 """
28 
29 from __future__ import (absolute_import, division, print_function)
30 
31 import numpy as np
32 import matplotlib.path
33 from matplotlib.path import Path
34 import shapely
35 from shapely.geometry.collection import GeometryCollection
36 from shapely.geometry.linestring import LineString
37 from shapely.geometry.point import Point
38 from shapely.geometry.polygon import Polygon
39 from shapely.geometry.multilinestring import MultiLineString
40 from shapely.geometry.multipoint import MultiPoint
41 from shapely.geometry.multipolygon import MultiPolygon
42 
43 
44 def geos_to_path(shape):
45     """
46     Creates a list of :class:`matplotlib.path.Path` objects that describe
47     a shape.
48 
49     Args:
50 
51     * shape
52         A list, tuple or single instance of any of the following
53         types: :class:`shapely.geometry.point.Point`,
54         :class:`shapely.geometry.linestring.LineString`,
55         :class:`shapely.geometry.polygon.Polygon`,
56         :class:`shapely.geometry.multipoint.MultiPoint`,
57         :class:`shapely.geometry.multipolygon.MultiPolygon`,
58         :class:`shapely.geometry.multilinestring.MultiLineString`,
59         :class:`shapely.geometry.collection.GeometryCollection`,
60         or any type with a _as_mpl_path() method.
61 
62     Returns:
63         A list of :class:`matplotlib.path.Path` objects.
64 
65     """
66     if isinstance(shape, (list, tuple)):
67         paths = []
68         for shp in shape:
69             paths.extend(geos_to_path(shp))
70         return paths
71 
72     if isinstance(shape, (LineString, Point)):
73         return [Path(np.vstack(shape.xy).T)]
74     elif isinstance(shape, Polygon):
75         def poly_codes(poly):
76             codes = np.ones(len(poly.xy[0])) * Path.LINETO
77             codes[0] = Path.MOVETO
78             return codes
79         if shape.is_empty:
80             return []
81         vertices = np.concatenate([np.array(shape.exterior.xy)] +
82                                   [np.array(ring.xy) for ring in
83                                    shape.interiors], 1).T
84         codes = np.concatenate([poly_codes(shape.exterior)] +
85                                [poly_codes(ring) for ring in shape.interiors])
86         return [Path(vertices, codes)]
87     elif isinstance(shape, (MultiPolygon, GeometryCollection, MultiLineString,
88                             MultiPoint)):
89         paths = []
90         for geom in shape.geoms:
91             paths.extend(geos_to_path(geom))
92         return paths
93     elif hasattr(shape, '_as_mpl_path'):
94         vertices, codes = shape._as_mpl_path()
95         return [Path(vertices, codes)]
96     else:
97         raise ValueError('Unsupported shape type {}.'.format(type(shape)))
98 
99 
100 def path_segments(path, transform=None, remove_nans=False, clip=None,
101                   quantize=False, simplify=False, curves=False,
102                   stroke_width=1.0, snap=False):
103     """
104     Creates an array of vertices and a corresponding array of codes from a
105     :class:`matplotlib.path.Path`.
106 
107     Args:
108 
109     * path
110         A :class:`matplotlib.path.Path` instance.
111 
112     Kwargs:
113         See :func:`matplotlib.path.iter_segments` for details of the keyword
114         arguments.
115 
116     Returns:
117         A (vertices, codes) tuple, where vertices is a numpy array of
118         coordinates, and codes is a numpy array of matplotlib path codes.
119         See :class:`matplotlib.path.Path` for information on the types of
120         codes and their meanings.
121 
122     """
123     # XXX assigned to avoid a ValueError inside the mpl C code...
124     a = transform, remove_nans, clip, quantize, simplify, curves
125 
126     # Series of cleanups and conversions to the path e.g. it
127     # can convert curved segments to line segments.
128     vertices, codes = matplotlib.path.cleanup_path(path, transform,
129                                                    remove_nans, clip,
130                                                    snap, stroke_width,
131                                                    simplify, curves)
132 
133     # Remove the final vertex (with code 0)
134     return vertices[:-1, :], codes[:-1]
135 
136 
137 # Matplotlib v1.3+ deprecates the use of matplotlib.path.cleanup_path. Instead
138 # there is a method on a Path instance to simplify this.
139 if hasattr(matplotlib.path.Path, 'cleaned'):
140     _path_segments_doc = path_segments.__doc__
141 
142     def path_segments(path, **kwargs):
143         pth = path.cleaned(**kwargs)
144         return pth.vertices[:-1, :], pth.codes[:-1]
145 
146     path_segments.__doc__ = _path_segments_doc
147 
148 
149 def path_to_geos(path, force_ccw=False):
150     """
151     Creates a list of Shapely geometric objects from a
152     :class:`matplotlib.path.Path`.
153 
154     Args:
155 
156     * path
157         A :class:`matplotlib.path.Path` instance.
158 
159     Kwargs:
160 
161     * force_ccw
162         Boolean flag determining whether the path can be inverted to enforce
163         ccw.
164 
165     Returns:
166         A list of :class:`shapely.geometry.polygon.Polygon`,
167         :class:`shapely.geometry.linestring.LineString` and/or
168         :class:`shapely.geometry.multilinestring.MultiLineString` instances.
169 
170     """
171     # Convert path into numpy array of vertices (and associated codes)
172     path_verts, path_codes = path_segments(path, curves=False)
173 
174     # Split into subarrays such that each subarray consists of connected
175     # line segments based on the start of each one being marked by a
176     # matplotlib MOVETO code.
177     verts_split_inds = np.where(path_codes == Path.MOVETO)[0]
178     verts_split = np.split(path_verts, verts_split_inds)
179     codes_split = np.split(path_codes, verts_split_inds)
180 
181     # Iterate through the vertices generating a list of
182     # (external_geom, [internal_polygons]) tuples.
183     collection = []
184     for path_verts, path_codes in zip(verts_split, codes_split):
185         if len(path_verts) == 0:
186             continue
187 
188         # XXX A path can be given which does not end with close poly, in that
189         # situation, we have to guess?
190         # XXX Implement a point
191         if (path_verts.shape[0] > 2 and
192                 (path_codes[-1] == Path.CLOSEPOLY or
193                  all(path_verts[0, :] == path_verts[-1, :]))):
194             if path_codes[-1] == Path.CLOSEPOLY:
195                 geom = Polygon(path_verts[:-1, :])
196             else:
197                 geom = Polygon(path_verts)
198         else:
199             geom = LineString(path_verts)
200 
201         # If geom is a Polygon and is contained within the last geom in
202         # collection, add it to its list of internal polygons, otherwise
203         # simple append it as a  new external geom.
204         if geom.is_empty:
205             pass
206         elif (len(collection) > 0 and
207                 isinstance(collection[-1][0], Polygon) and
208                 isinstance(geom, Polygon) and
209                 collection[-1][0].contains(geom.exterior)):
210             collection[-1][1].append(geom.exterior)
211         else:
212             collection.append((geom, []))
213 
214     # Convert each (external_geom, [internal_polygons]) pair into a
215     # a shapely Polygon that encapsulates the internal polygons, if the
216     # external geom is a LineSting leave it alone.
217     geom_collection = []
218     for external_geom, internal_polys in collection:
219         if internal_polys:
220             # XXX worry about islands within lakes
221             geom = Polygon(external_geom.exterior, internal_polys)
222         else:
223             geom = external_geom
224 
225         # Correctly orientate the polygon (ccw)
226         if force_ccw and not geom.exterior.is_ccw:
227             geom = shapely.geometry.polygon.orient(geom)
228 
229         geom_collection.append(geom)
230 
231     # If the geom_collection only contains LineStrings combine them
232     # into a single MultiLinestring.
233     if geom_collection and all(isinstance(geom, LineString) for
234                                geom in geom_collection):
235         geom_collection = [MultiLineString(geom_collection)]
236 
237     # Remove any zero area Polygons
238     not_zero_poly = lambda geom: ((isinstance(geom, Polygon) and
239                                    not geom._is_empty and geom.area != 0) or
240                                   not isinstance(geom, Polygon))
241     result = list(filter(not_zero_poly, geom_collection))
242 
243     return result
244
```
--- 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/lib/cartopy/mpl/patch.py b/lib/cartopy/mpl/patch.py
--- a/lib/cartopy/mpl/patch.py
+++ b/lib/cartopy/mpl/patch.py
@@ -213,7 +213,7 @@
 
     # Convert each (external_geom, [internal_polygons]) pair into a
     # a shapely Polygon that encapsulates the internal polygons, if the
-    # external geom is a LineSting leave it alone.
+    # external geom is a LineString leave it alone.
     geom_collection = []
     for external_geom, internal_polys in collection:
         if internal_polys:
@@ -223,8 +223,9 @@
             geom = external_geom
 
         # Correctly orientate the polygon (ccw)
-        if force_ccw and not geom.exterior.is_ccw:
-            geom = shapely.geometry.polygon.orient(geom)
+        if isinstance(geom, Polygon):
+            if force_ccw and not geom.exterior.is_ccw:
+                geom = shapely.geometry.polygon.orient(geom)
 
         geom_collection.append(geom)

{"golden_diff": "diff --git a/lib/cartopy/mpl/patch.py b/lib/cartopy/mpl/patch.py\n--- a/lib/cartopy/mpl/patch.py\n+++ b/lib/cartopy/mpl/patch.py\n@@ -213,7 +213,7 @@\n \n     # Convert each (external_geom, [internal_polygons]) pair into a\n     # a shapely Polygon that encapsulates the internal polygons, if the\n-    # external geom is a LineSting leave it alone.\n+    # external geom is a LineString leave it alone.\n     geom_collection = []\n     for external_geom, internal_polys in collection:\n         if internal_polys:\n@@ -223,8 +223,9 @@\n             geom = external_geom\n \n         # Correctly orientate the polygon (ccw)\n-        if force_ccw and not geom.exterior.is_ccw:\n-            geom = shapely.geometry.polygon.orient(geom)\n+        if isinstance(geom, Polygon):\n+            if force_ccw and not geom.exterior.is_ccw:\n+                geom = shapely.geometry.polygon.orient(geom)\n \n         geom_collection.append(geom)\n", "issue": "AttributeError: 'LineString' object has no attribute 'exterior'\nRunning the first example from #13 prints this (snipped) traceback:\n\n```\n  File \".../matplotlib/transforms.py\", line 2227, in transform_path_non_affine\n    return self._a.transform_path_non_affine(path)\n  File \".../Cartopy-0.12.x-py2.7-linux-x86_64.egg/cartopy/mpl/geoaxes.py\", line 169, in transform_path_non_affine\n    getattr(self, 'force_path_ccw', False))\n  File \".../Cartopy-0.12.x-py2.7-linux-x86_64.egg/cartopy/mpl/patch.py\", line 226, in path_to_geos\n    if force_ccw and not geom.exterior.is_ccw:\nAttributeError: 'LineString' object has no attribute 'exterior'\n```\n\nI'm not sure if this can be triggered by other (i.e., not otherwise known to be broken) usage.\n\n", "before_files": [{"content": "# (C) British Crown Copyright 2011 - 2014, Met Office\n#\n# This file is part of cartopy.\n#\n# cartopy is free software: you can redistribute it and/or modify it under\n# the terms of the GNU Lesser General Public License as published by the\n# Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# cartopy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public License\n# along with cartopy.  If not, see <http://www.gnu.org/licenses/>.\n\"\"\"\nProvides shapely geometry <-> matplotlib path support.\n\n\nSee also `Shapely Geometric Objects <see_also_shapely>`_\nand `Matplotlib Path API <http://matplotlib.org/api/path_api.html>`_.\n\n.. see_also_shapely:\n   http://toblerity.github.com/shapely/manual.html#geometric-objects\n\n\"\"\"\n\nfrom __future__ import (absolute_import, division, print_function)\n\nimport numpy as np\nimport matplotlib.path\nfrom matplotlib.path import Path\nimport shapely\nfrom shapely.geometry.collection import GeometryCollection\nfrom shapely.geometry.linestring import LineString\nfrom shapely.geometry.point import Point\nfrom shapely.geometry.polygon import Polygon\nfrom shapely.geometry.multilinestring import MultiLineString\nfrom shapely.geometry.multipoint import MultiPoint\nfrom shapely.geometry.multipolygon import MultiPolygon\n\n\ndef geos_to_path(shape):\n    \"\"\"\n    Creates a list of :class:`matplotlib.path.Path` objects that describe\n    a shape.\n\n    Args:\n\n    * shape\n        A list, tuple or single instance of any of the following\n        types: :class:`shapely.geometry.point.Point`,\n        :class:`shapely.geometry.linestring.LineString`,\n        :class:`shapely.geometry.polygon.Polygon`,\n        :class:`shapely.geometry.multipoint.MultiPoint`,\n        :class:`shapely.geometry.multipolygon.MultiPolygon`,\n        :class:`shapely.geometry.multilinestring.MultiLineString`,\n        :class:`shapely.geometry.collection.GeometryCollection`,\n        or any type with a _as_mpl_path() method.\n\n    Returns:\n        A list of :class:`matplotlib.path.Path` objects.\n\n    \"\"\"\n    if isinstance(shape, (list, tuple)):\n        paths = []\n        for shp in shape:\n            paths.extend(geos_to_path(shp))\n        return paths\n\n    if isinstance(shape, (LineString, Point)):\n        return [Path(np.vstack(shape.xy).T)]\n    elif isinstance(shape, Polygon):\n        def poly_codes(poly):\n            codes = np.ones(len(poly.xy[0])) * Path.LINETO\n            codes[0] = Path.MOVETO\n            return codes\n        if shape.is_empty:\n            return []\n        vertices = np.concatenate([np.array(shape.exterior.xy)] +\n                                  [np.array(ring.xy) for ring in\n                                   shape.interiors], 1).T\n        codes = np.concatenate([poly_codes(shape.exterior)] +\n                               [poly_codes(ring) for ring in shape.interiors])\n        return [Path(vertices, codes)]\n    elif isinstance(shape, (MultiPolygon, GeometryCollection, MultiLineString,\n                            MultiPoint)):\n        paths = []\n        for geom in shape.geoms:\n            paths.extend(geos_to_path(geom))\n        return paths\n    elif hasattr(shape, '_as_mpl_path'):\n        vertices, codes = shape._as_mpl_path()\n        return [Path(vertices, codes)]\n    else:\n        raise ValueError('Unsupported shape type {}.'.format(type(shape)))\n\n\ndef path_segments(path, transform=None, remove_nans=False, clip=None,\n                  quantize=False, simplify=False, curves=False,\n                  stroke_width=1.0, snap=False):\n    \"\"\"\n    Creates an array of vertices and a corresponding array of codes from a\n    :class:`matplotlib.path.Path`.\n\n    Args:\n\n    * path\n        A :class:`matplotlib.path.Path` instance.\n\n    Kwargs:\n        See :func:`matplotlib.path.iter_segments` for details of the keyword\n        arguments.\n\n    Returns:\n        A (vertices, codes) tuple, where vertices is a numpy array of\n        coordinates, and codes is a numpy array of matplotlib path codes.\n        See :class:`matplotlib.path.Path` for information on the types of\n        codes and their meanings.\n\n    \"\"\"\n    # XXX assigned to avoid a ValueError inside the mpl C code...\n    a = transform, remove_nans, clip, quantize, simplify, curves\n\n    # Series of cleanups and conversions to the path e.g. it\n    # can convert curved segments to line segments.\n    vertices, codes = matplotlib.path.cleanup_path(path, transform,\n                                                   remove_nans, clip,\n                                                   snap, stroke_width,\n                                                   simplify, curves)\n\n    # Remove the final vertex (with code 0)\n    return vertices[:-1, :], codes[:-1]\n\n\n# Matplotlib v1.3+ deprecates the use of matplotlib.path.cleanup_path. Instead\n# there is a method on a Path instance to simplify this.\nif hasattr(matplotlib.path.Path, 'cleaned'):\n    _path_segments_doc = path_segments.__doc__\n\n    def path_segments(path, **kwargs):\n        pth = path.cleaned(**kwargs)\n        return pth.vertices[:-1, :], pth.codes[:-1]\n\n    path_segments.__doc__ = _path_segments_doc\n\n\ndef path_to_geos(path, force_ccw=False):\n    \"\"\"\n    Creates a list of Shapely geometric objects from a\n    :class:`matplotlib.path.Path`.\n\n    Args:\n\n    * path\n        A :class:`matplotlib.path.Path` instance.\n\n    Kwargs:\n\n    * force_ccw\n        Boolean flag determining whether the path can be inverted to enforce\n        ccw.\n\n    Returns:\n        A list of :class:`shapely.geometry.polygon.Polygon`,\n        :class:`shapely.geometry.linestring.LineString` and/or\n        :class:`shapely.geometry.multilinestring.MultiLineString` instances.\n\n    \"\"\"\n    # Convert path into numpy array of vertices (and associated codes)\n    path_verts, path_codes = path_segments(path, curves=False)\n\n    # Split into subarrays such that each subarray consists of connected\n    # line segments based on the start of each one being marked by a\n    # matplotlib MOVETO code.\n    verts_split_inds = np.where(path_codes == Path.MOVETO)[0]\n    verts_split = np.split(path_verts, verts_split_inds)\n    codes_split = np.split(path_codes, verts_split_inds)\n\n    # Iterate through the vertices generating a list of\n    # (external_geom, [internal_polygons]) tuples.\n    collection = []\n    for path_verts, path_codes in zip(verts_split, codes_split):\n        if len(path_verts) == 0:\n            continue\n\n        # XXX A path can be given which does not end with close poly, in that\n        # situation, we have to guess?\n        # XXX Implement a point\n        if (path_verts.shape[0] > 2 and\n                (path_codes[-1] == Path.CLOSEPOLY or\n                 all(path_verts[0, :] == path_verts[-1, :]))):\n            if path_codes[-1] == Path.CLOSEPOLY:\n                geom = Polygon(path_verts[:-1, :])\n            else:\n                geom = Polygon(path_verts)\n        else:\n            geom = LineString(path_verts)\n\n        # If geom is a Polygon and is contained within the last geom in\n        # collection, add it to its list of internal polygons, otherwise\n        # simple append it as a  new external geom.\n        if geom.is_empty:\n            pass\n        elif (len(collection) > 0 and\n                isinstance(collection[-1][0], Polygon) and\n                isinstance(geom, Polygon) and\n                collection[-1][0].contains(geom.exterior)):\n            collection[-1][1].append(geom.exterior)\n        else:\n            collection.append((geom, []))\n\n    # Convert each (external_geom, [internal_polygons]) pair into a\n    # a shapely Polygon that encapsulates the internal polygons, if the\n    # external geom is a LineSting leave it alone.\n    geom_collection = []\n    for external_geom, internal_polys in collection:\n        if internal_polys:\n            # XXX worry about islands within lakes\n            geom = Polygon(external_geom.exterior, internal_polys)\n        else:\n            geom = external_geom\n\n        # Correctly orientate the polygon (ccw)\n        if force_ccw and not geom.exterior.is_ccw:\n            geom = shapely.geometry.polygon.orient(geom)\n\n        geom_collection.append(geom)\n\n    # If the geom_collection only contains LineStrings combine them\n    # into a single MultiLinestring.\n    if geom_collection and all(isinstance(geom, LineString) for\n                               geom in geom_collection):\n        geom_collection = [MultiLineString(geom_collection)]\n\n    # Remove any zero area Polygons\n    not_zero_poly = lambda geom: ((isinstance(geom, Polygon) and\n                                   not geom._is_empty and geom.area != 0) or\n                                  not isinstance(geom, Polygon))\n    result = list(filter(not_zero_poly, geom_collection))\n\n    return result\n", "path": "lib/cartopy/mpl/patch.py"}], "after_files": [{"content": "# (C) British Crown Copyright 2011 - 2014, Met Office\n#\n# This file is part of cartopy.\n#\n# cartopy is free software: you can redistribute it and/or modify it under\n# the terms of the GNU Lesser General Public License as published by the\n# Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# cartopy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public License\n# along with cartopy.  If not, see <http://www.gnu.org/licenses/>.\n\"\"\"\nProvides shapely geometry <-> matplotlib path support.\n\n\nSee also `Shapely Geometric Objects <see_also_shapely>`_\nand `Matplotlib Path API <http://matplotlib.org/api/path_api.html>`_.\n\n.. see_also_shapely:\n   http://toblerity.github.com/shapely/manual.html#geometric-objects\n\n\"\"\"\n\nfrom __future__ import (absolute_import, division, print_function)\n\nimport numpy as np\nimport matplotlib.path\nfrom matplotlib.path import Path\nimport shapely\nfrom shapely.geometry.collection import GeometryCollection\nfrom shapely.geometry.linestring import LineString\nfrom shapely.geometry.point import Point\nfrom shapely.geometry.polygon import Polygon\nfrom shapely.geometry.multilinestring import MultiLineString\nfrom shapely.geometry.multipoint import MultiPoint\nfrom shapely.geometry.multipolygon import MultiPolygon\n\n\ndef geos_to_path(shape):\n    \"\"\"\n    Creates a list of :class:`matplotlib.path.Path` objects that describe\n    a shape.\n\n    Args:\n\n    * shape\n        A list, tuple or single instance of any of the following\n        types: :class:`shapely.geometry.point.Point`,\n        :class:`shapely.geometry.linestring.LineString`,\n        :class:`shapely.geometry.polygon.Polygon`,\n        :class:`shapely.geometry.multipoint.MultiPoint`,\n        :class:`shapely.geometry.multipolygon.MultiPolygon`,\n        :class:`shapely.geometry.multilinestring.MultiLineString`,\n        :class:`shapely.geometry.collection.GeometryCollection`,\n        or any type with a _as_mpl_path() method.\n\n    Returns:\n        A list of :class:`matplotlib.path.Path` objects.\n\n    \"\"\"\n    if isinstance(shape, (list, tuple)):\n        paths = []\n        for shp in shape:\n            paths.extend(geos_to_path(shp))\n        return paths\n\n    if isinstance(shape, (LineString, Point)):\n        return [Path(np.vstack(shape.xy).T)]\n    elif isinstance(shape, Polygon):\n        def poly_codes(poly):\n            codes = np.ones(len(poly.xy[0])) * Path.LINETO\n            codes[0] = Path.MOVETO\n            return codes\n        if shape.is_empty:\n            return []\n        vertices = np.concatenate([np.array(shape.exterior.xy)] +\n                                  [np.array(ring.xy) for ring in\n                                   shape.interiors], 1).T\n        codes = np.concatenate([poly_codes(shape.exterior)] +\n                               [poly_codes(ring) for ring in shape.interiors])\n        return [Path(vertices, codes)]\n    elif isinstance(shape, (MultiPolygon, GeometryCollection, MultiLineString,\n                            MultiPoint)):\n        paths = []\n        for geom in shape.geoms:\n            paths.extend(geos_to_path(geom))\n        return paths\n    elif hasattr(shape, '_as_mpl_path'):\n        vertices, codes = shape._as_mpl_path()\n        return [Path(vertices, codes)]\n    else:\n        raise ValueError('Unsupported shape type {}.'.format(type(shape)))\n\n\ndef path_segments(path, transform=None, remove_nans=False, clip=None,\n                  quantize=False, simplify=False, curves=False,\n                  stroke_width=1.0, snap=False):\n    \"\"\"\n    Creates an array of vertices and a corresponding array of codes from a\n    :class:`matplotlib.path.Path`.\n\n    Args:\n\n    * path\n        A :class:`matplotlib.path.Path` instance.\n\n    Kwargs:\n        See :func:`matplotlib.path.iter_segments` for details of the keyword\n        arguments.\n\n    Returns:\n        A (vertices, codes) tuple, where vertices is a numpy array of\n        coordinates, and codes is a numpy array of matplotlib path codes.\n        See :class:`matplotlib.path.Path` for information on the types of\n        codes and their meanings.\n\n    \"\"\"\n    # XXX assigned to avoid a ValueError inside the mpl C code...\n    a = transform, remove_nans, clip, quantize, simplify, curves\n\n    # Series of cleanups and conversions to the path e.g. it\n    # can convert curved segments to line segments.\n    vertices, codes = matplotlib.path.cleanup_path(path, transform,\n                                                   remove_nans, clip,\n                                                   snap, stroke_width,\n                                                   simplify, curves)\n\n    # Remove the final vertex (with code 0)\n    return vertices[:-1, :], codes[:-1]\n\n\n# Matplotlib v1.3+ deprecates the use of matplotlib.path.cleanup_path. Instead\n# there is a method on a Path instance to simplify this.\nif hasattr(matplotlib.path.Path, 'cleaned'):\n    _path_segments_doc = path_segments.__doc__\n\n    def path_segments(path, **kwargs):\n        pth = path.cleaned(**kwargs)\n        return pth.vertices[:-1, :], pth.codes[:-1]\n\n    path_segments.__doc__ = _path_segments_doc\n\n\ndef path_to_geos(path, force_ccw=False):\n    \"\"\"\n    Creates a list of Shapely geometric objects from a\n    :class:`matplotlib.path.Path`.\n\n    Args:\n\n    * path\n        A :class:`matplotlib.path.Path` instance.\n\n    Kwargs:\n\n    * force_ccw\n        Boolean flag determining whether the path can be inverted to enforce\n        ccw.\n\n    Returns:\n        A list of :class:`shapely.geometry.polygon.Polygon`,\n        :class:`shapely.geometry.linestring.LineString` and/or\n        :class:`shapely.geometry.multilinestring.MultiLineString` instances.\n\n    \"\"\"\n    # Convert path into numpy array of vertices (and associated codes)\n    path_verts, path_codes = path_segments(path, curves=False)\n\n    # Split into subarrays such that each subarray consists of connected\n    # line segments based on the start of each one being marked by a\n    # matplotlib MOVETO code.\n    verts_split_inds = np.where(path_codes == Path.MOVETO)[0]\n    verts_split = np.split(path_verts, verts_split_inds)\n    codes_split = np.split(path_codes, verts_split_inds)\n\n    # Iterate through the vertices generating a list of\n    # (external_geom, [internal_polygons]) tuples.\n    collection = []\n    for path_verts, path_codes in zip(verts_split, codes_split):\n        if len(path_verts) == 0:\n            continue\n\n        # XXX A path can be given which does not end with close poly, in that\n        # situation, we have to guess?\n        # XXX Implement a point\n        if (path_verts.shape[0] > 2 and\n                (path_codes[-1] == Path.CLOSEPOLY or\n                 all(path_verts[0, :] == path_verts[-1, :]))):\n            if path_codes[-1] == Path.CLOSEPOLY:\n                geom = Polygon(path_verts[:-1, :])\n            else:\n                geom = Polygon(path_verts)\n        else:\n            geom = LineString(path_verts)\n\n        # If geom is a Polygon and is contained within the last geom in\n        # collection, add it to its list of internal polygons, otherwise\n        # simple append it as a  new external geom.\n        if geom.is_empty:\n            pass\n        elif (len(collection) > 0 and\n                isinstance(collection[-1][0], Polygon) and\n                isinstance(geom, Polygon) and\n                collection[-1][0].contains(geom.exterior)):\n            collection[-1][1].append(geom.exterior)\n        else:\n            collection.append((geom, []))\n\n    # Convert each (external_geom, [internal_polygons]) pair into a\n    # a shapely Polygon that encapsulates the internal polygons, if the\n    # external geom is a LineString leave it alone.\n    geom_collection = []\n    for external_geom, internal_polys in collection:\n        if internal_polys:\n            # XXX worry about islands within lakes\n            geom = Polygon(external_geom.exterior, internal_polys)\n        else:\n            geom = external_geom\n\n        # Correctly orientate the polygon (ccw)\n        if isinstance(geom, Polygon):\n            if force_ccw and not geom.exterior.is_ccw:\n                geom = shapely.geometry.polygon.orient(geom)\n\n        geom_collection.append(geom)\n\n    # If the geom_collection only contains LineStrings combine them\n    # into a single MultiLinestring.\n    if geom_collection and all(isinstance(geom, LineString) for\n                               geom in geom_collection):\n        geom_collection = [MultiLineString(geom_collection)]\n\n    # Remove any zero area Polygons\n    not_zero_poly = lambda geom: ((isinstance(geom, Polygon) and\n                                   not geom._is_empty and geom.area != 0) or\n                                  not isinstance(geom, Polygon))\n    result = list(filter(not_zero_poly, geom_collection))\n\n    return result\n", "path": "lib/cartopy/mpl/patch.py"}]}