prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  ENH: preserve column order in read_file
  Idea from http://gis.stackexchange.com/questions/216963/preserve-column-order-of-geopandas-file-read/217084#217084
  
  For shapefiles, fiona saves the properties in the `meta` attribute as an OrderedDict, so we should be able to get the actual order of the columns in the file from that and rearrange the columns of the output accordingly.
  
  </issue>
  <code>
  [start of geopandas/io/file.py]
  1 import os
  2 
  3 import fiona
  4 import numpy as np
  5 from shapely.geometry import mapping
  6 
  7 from six import iteritems
  8 from geopandas import GeoDataFrame
  9 
  10 
  11 def read_file(filename, **kwargs):
  12     """
  13     Returns a GeoDataFrame from a file.
  14 
  15     *filename* is either the absolute or relative path to the file to be
  16     opened and *kwargs* are keyword args to be passed to the `open` method
  17     in the fiona library when opening the file. For more information on 
  18     possible keywords, type: ``import fiona; help(fiona.open)``
  19     """
  20     bbox = kwargs.pop('bbox', None)
  21     with fiona.open(filename, **kwargs) as f:
  22         crs = f.crs
  23         if bbox is not None:
  24             assert len(bbox)==4
  25             f_filt = f.filter(bbox=bbox)
  26         else:
  27             f_filt = f
  28         gdf = GeoDataFrame.from_features(f_filt, crs=crs)
  29 
  30     return gdf
  31 
  32 
  33 def to_file(df, filename, driver="ESRI Shapefile", schema=None,
  34             **kwargs):
  35     """
  36     Write this GeoDataFrame to an OGR data source
  37 
  38     A dictionary of supported OGR providers is available via:
  39     >>> import fiona
  40     >>> fiona.supported_drivers
  41 
  42     Parameters
  43     ----------
  44     df : GeoDataFrame to be written
  45     filename : string
  46         File path or file handle to write to.
  47     driver : string, default 'ESRI Shapefile'
  48         The OGR format driver used to write the vector file.
  49     schema : dict, default None
  50         If specified, the schema dictionary is passed to Fiona to
  51         better control how the file is written. If None, GeoPandas
  52         will determine the schema based on each column's dtype
  53 
  54     The *kwargs* are passed to fiona.open and can be used to write
  55     to multi-layer data, store data within archives (zip files), etc.
  56     """
  57     if schema is None:
  58         schema = infer_schema(df)
  59     filename = os.path.abspath(os.path.expanduser(filename))
  60     with fiona.open(filename, 'w', driver=driver, crs=df.crs,
  61                     schema=schema, **kwargs) as c:
  62         for feature in df.iterfeatures():
  63             c.write(feature)
  64 
  65 
  66 def infer_schema(df):
  67     try:
  68         from collections import OrderedDict
  69     except ImportError:
  70         from ordereddict import OrderedDict
  71 
  72     def convert_type(in_type):
  73         if in_type == object:
  74             return 'str'
  75         out_type = type(np.asscalar(np.zeros(1, in_type))).__name__
  76         if out_type == 'long':
  77             out_type = 'int'
  78         return out_type
  79 
  80     properties = OrderedDict([
  81         (col, convert_type(_type)) for col, _type in
  82         zip(df.columns, df.dtypes) if col != df._geometry_column_name
  83     ])
  84 
  85     geom_type = _common_geom_type(df)
  86     if not geom_type:
  87         raise ValueError("Geometry column cannot contain mutiple "
  88                          "geometry types when writing to file.")
  89 
  90     schema = {'geometry': geom_type, 'properties': properties}
  91 
  92     return schema
  93 
  94 
  95 def _common_geom_type(df):
  96     # Need to check geom_types before we write to file...
  97     # Some (most?) providers expect a single geometry type:
  98     # Point, LineString, or Polygon
  99     geom_types = df.geometry.geom_type.unique()
  100 
  101     from os.path import commonprefix   # To find longest common prefix
  102     geom_type = commonprefix([g[::-1] for g in geom_types if g])[::-1]  # Reverse
  103     if not geom_type:
  104         geom_type = None
  105 
  106     return geom_type
  107
  [end of geopandas/io/file.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/geopandas/io/file.py b/geopandas/io/file.py
  --- a/geopandas/io/file.py
  +++ b/geopandas/io/file.py
  @@ -14,7 +14,7 @@
   
       *filename* is either the absolute or relative path to the file to be
       opened and *kwargs* are keyword args to be passed to the `open` method
  -    in the fiona library when opening the file. For more information on 
  +    in the fiona library when opening the file. For more information on
       possible keywords, type: ``import fiona; help(fiona.open)``
       """
       bbox = kwargs.pop('bbox', None)
  @@ -27,6 +27,10 @@
               f_filt = f
           gdf = GeoDataFrame.from_features(f_filt, crs=crs)
   
  +        # re-order with column order from metadata, with geometry last
  +        columns = list(f.meta["schema"]["properties"]) + ["geometry"]
  +        gdf = gdf[columns]
  +
       return gdf
  
verification_info: {"golden_diff": "diff --git a/geopandas/io/file.py b/geopandas/io/file.py\n--- a/geopandas/io/file.py\n+++ b/geopandas/io/file.py\n@@ -14,7 +14,7 @@\n \n     *filename* is either the absolute or relative path to the file to be\n     opened and *kwargs* are keyword args to be passed to the `open` method\n-    in the fiona library when opening the file. For more information on \n+    in the fiona library when opening the file. For more information on\n     possible keywords, type: ``import fiona; help(fiona.open)``\n     \"\"\"\n     bbox = kwargs.pop('bbox', None)\n@@ -27,6 +27,10 @@\n             f_filt = f\n         gdf = GeoDataFrame.from_features(f_filt, crs=crs)\n \n+        # re-order with column order from metadata, with geometry last\n+        columns = list(f.meta[\"schema\"][\"properties\"]) + [\"geometry\"]\n+        gdf = gdf[columns]\n+\n     return gdf\n", "issue": "ENH: preserve column order in read_file\nIdea from http://gis.stackexchange.com/questions/216963/preserve-column-order-of-geopandas-file-read/217084#217084\r\n\r\nFor shapefiles, fiona saves the properties in the `meta` attribute as an OrderedDict, so we should be able to get the actual order of the columns in the file from that and rearrange the columns of the output accordingly.\n", "before_files": [{"content": "import os\n\nimport fiona\nimport numpy as np\nfrom shapely.geometry import mapping\n\nfrom six import iteritems\nfrom geopandas import GeoDataFrame\n\n\ndef read_file(filename, **kwargs):\n    \"\"\"\n    Returns a GeoDataFrame from a file.\n\n    *filename* is either the absolute or relative path to the file to be\n    opened and *kwargs* are keyword args to be passed to the `open` method\n    in the fiona library when opening the file. For more information on \n    possible keywords, type: ``import fiona; help(fiona.open)``\n    \"\"\"\n    bbox = kwargs.pop('bbox', None)\n    with fiona.open(filename, **kwargs) as f:\n        crs = f.crs\n        if bbox is not None:\n            assert len(bbox)==4\n            f_filt = f.filter(bbox=bbox)\n        else:\n            f_filt = f\n        gdf = GeoDataFrame.from_features(f_filt, crs=crs)\n\n    return gdf\n\n\ndef to_file(df, filename, driver=\"ESRI Shapefile\", schema=None,\n            **kwargs):\n    \"\"\"\n    Write this GeoDataFrame to an OGR data source\n\n    A dictionary of supported OGR providers is available via:\n    >>> import fiona\n    >>> fiona.supported_drivers\n\n    Parameters\n    ----------\n    df : GeoDataFrame to be written\n    filename : string\n        File path or file handle to write to.\n    driver : string, default 'ESRI Shapefile'\n        The OGR format driver used to write the vector file.\n    schema : dict, default None\n        If specified, the schema dictionary is passed to Fiona to\n        better control how the file is written. If None, GeoPandas\n        will determine the schema based on each column's dtype\n\n    The *kwargs* are passed to fiona.open and can be used to write\n    to multi-layer data, store data within archives (zip files), etc.\n    \"\"\"\n    if schema is None:\n        schema = infer_schema(df)\n    filename = os.path.abspath(os.path.expanduser(filename))\n    with fiona.open(filename, 'w', driver=driver, crs=df.crs,\n                    schema=schema, **kwargs) as c:\n        for feature in df.iterfeatures():\n            c.write(feature)\n\n\ndef infer_schema(df):\n    try:\n        from collections import OrderedDict\n    except ImportError:\n        from ordereddict import OrderedDict\n\n    def convert_type(in_type):\n        if in_type == object:\n            return 'str'\n        out_type = type(np.asscalar(np.zeros(1, in_type))).__name__\n        if out_type == 'long':\n            out_type = 'int'\n        return out_type\n\n    properties = OrderedDict([\n        (col, convert_type(_type)) for col, _type in\n        zip(df.columns, df.dtypes) if col != df._geometry_column_name\n    ])\n\n    geom_type = _common_geom_type(df)\n    if not geom_type:\n        raise ValueError(\"Geometry column cannot contain mutiple \"\n                         \"geometry types when writing to file.\")\n\n    schema = {'geometry': geom_type, 'properties': properties}\n\n    return schema\n\n\ndef _common_geom_type(df):\n    # Need to check geom_types before we write to file...\n    # Some (most?) providers expect a single geometry type:\n    # Point, LineString, or Polygon\n    geom_types = df.geometry.geom_type.unique()\n\n    from os.path import commonprefix   # To find longest common prefix\n    geom_type = commonprefix([g[::-1] for g in geom_types if g])[::-1]  # Reverse\n    if not geom_type:\n        geom_type = None\n\n    return geom_type\n", "path": "geopandas/io/file.py"}]}