Repository: geopandas/geopandas

Issue:
GeoDataFrame.to_file fail on bool column
When converting GeoDataFrame with bool column to shp file, got following error
```sh
ValueError: 'bool' is not in list
```


Discussion:
I believe the issue is that shapefiles [do not have a notion of a boolean value](https://gis.stackexchange.com/questions/24041/adding-boolean-yes-no-field-in-arcgis-desktop). Instead they're treated as an [integer subtype](http://www.gdal.org/ogr__core_8h.html#a24d96814a798fa79bffd2b8ce6135284). It looks to me like `fiona` follows this curious convention. 

This is a `fiona` issue (the error is `fiona/ogrext.pyx in fiona.ogrext.WritingSession.start (fiona/ogrext.c:16869)()`), not a `geopandas` one, anyway.
yes, I changed the type to integer to fix it.
maybe there could be a feature of `GeoPandas` using a parameter, like `transform_bool=['T', 'F']` to do this automatically
It is indeed an error in fiona, but it is geopandas that created an 'invalid' schema

```
In [7]: gdf = geopandas.GeoDataFrame({'a':[1, 2], 'b': [True, False]}, geometry=[shapely.geometry.Point(0,0), shapely.geometry.Point(1,1)])

In [10]: geopandas.io.file.infer_schema(gdf)
Out[10]: {'geometry': 'Point', 'properties': OrderedDict([('a', 'int'), ('b', 'bool')])}
```

While, I think fiona only accepts those:

```
In [16]: fiona.FIELD_TYPES_MAP
Out[16]: 
{'date': fiona.rfc3339.FionaDateType,
 'datetime': fiona.rfc3339.FionaDateTimeType,
 'float': float,
 'int': int,
 'str': str,
 'time': fiona.rfc3339.FionaTimeType}
```

So we could error early one providing a more custom error message, if we want.

I would leave it to the user to transform the column as they want (we could also not offer roundtrip-ability with `read_file`). Maybe fiona could try to support booleans with the int subtype if someone wants to do that effort.
This thread was mentioned in my answer on StackOverflow: [Saving the dataframe to shapefile using geopandas in python](https://stackoverflow.com/questions/42221358/).

Proposed solution is for the user to recast the columns of boolean type over to integer:
~~~python
df['c'] = df['c'].astype('int')
~~~

or as a function that applies this to all columns in the gdf:

~~~python
def gdf_bool_to_int(gdf):
    """For a given GeoDataFrame, returns a copy that
    recasts all `bool`-type columns as `int`.

    GeoDataFrame -> GeoDataFrame"""
    df = gdf.copy()
    coltypes = gpd.io.file.infer_schema(df)['properties']
    for c in coltypes.items():
        if c[1] == 'bool':
            colname = c[0]
            df[colname] = df[colname].astype('int')
    return df
~~~

Feel free to update the answer there if I'm missing something.

Resolving patch:
diff --git a/geopandas/io/file.py b/geopandas/io/file.py
--- a/geopandas/io/file.py
+++ b/geopandas/io/file.py
@@ -113,16 +113,20 @@ def infer_schema(df):
     except ImportError:
         from ordereddict import OrderedDict
 
-    def convert_type(in_type):
+    def convert_type(column, in_type):
         if in_type == object:
             return 'str'
         out_type = type(np.asscalar(np.zeros(1, in_type))).__name__
         if out_type == 'long':
             out_type = 'int'
+        if out_type == 'bool':
+            raise ValueError('column "{}" is boolean type, '.format(column) +
+                             'which is unsupported in file writing. '
+                             'Consider casting the column to int type.')
         return out_type
 
     properties = OrderedDict([
-        (col, convert_type(_type)) for col, _type in
+        (col, convert_type(col, _type)) for col, _type in
         zip(df.columns, df.dtypes) if col != df._geometry_column_name
     ])
 


Test patch:
diff --git a/geopandas/tests/test_geodataframe.py b/geopandas/tests/test_geodataframe.py
--- a/geopandas/tests/test_geodataframe.py
+++ b/geopandas/tests/test_geodataframe.py
@@ -310,6 +310,16 @@ def test_to_file(self):
         assert len(df3) == 2
         assert np.alltrue(df3['Name'].values == self.line_paths)
 
+    def test_to_file_bool(self):
+        """Test error raise when writing with a boolean column (GH #437)."""
+
+        # still want a temp dir in case this test passes
+        tempfilename = os.path.join(self.tempdir, 'boros.shp')
+        df_with_bool = self.df.copy()
+        df_with_bool['bool_column'] = True
+        with pytest.raises(ValueError):
+            df_with_bool.to_file(tempfilename)
+
     def test_to_file_types(self):
         """ Test various integer type columns (GH#93) """
         tempfilename = os.path.join(self.tempdir, 'int.shp')