Skip to content

Commit

Permalink
Add GeoJSON to supported formats and layer selection by index.
Browse files Browse the repository at this point in the history
  • Loading branch information
sgillies committed Jun 6, 2013
1 parent dcc012e commit 6d9911b
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 18 deletions.
66 changes: 60 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,15 @@ http://www.lfd.uci.edu/~gohlke/pythonlibs/#fiona and coming eventually to PyPI.
Usage
=====

Records are read from and written to ``file``-like `Collection` objects.
Records are mappings modeled on the GeoJSON format. They don't have any spatial
methods of their own, so if you want to do anything fancy with them you will
probably need Shapely or something like it. Here is an example of using Fiona
to read some records from one data file, change their geometry attributes, and
write them to a new data file.
Collections
-----------

Records are read from and written to ``file``-like `Collection` objects
returned from the ``fiona.open()`` function. Records are mappings modeled on
the GeoJSON format. They don't have any spatial methods of their own, so if you
want to do anything fancy with them you will probably need Shapely or something
like it. Here is an example of using Fiona to read some records from one data
file, change their geometry attributes, and write them to a new data file.

.. sourcecode:: python

Expand Down Expand Up @@ -112,6 +115,57 @@ write them to a new data file.
# when its ``with`` block ends. This effectively executes
# ``sink.flush(); sink.close()``.

Collections from Multilayer data
--------------------------------

Collections can also be made from single layers within multilayer files or
directories of data. The target layer is specified by name or by its integer
index within the file or directory. The ``fiona.listlayers()`` function
provides an index ordered list of layer names.

.. sourcecode:: python

for i, layername in enumerate(fiona.listlayers('docs/data')):
with fiona.open('docs/data', layer=layername) as c:
print(i, layername, len(c))

# Output:
# 0 test_uk 48

Again, the layer can be specified by its index. In this case, ``layer=0`` and
``layer='test_uk'`` specify the same layer in the data file or directory.

.. sourcecode:: python

for i, layername in enumerate(fiona.listlayers('docs/data')):
with fiona.open('docs/data', layer=i) as c:
print(i, layername, len(c))

# Output:
# 0 test_uk 48

Collections from archives and virtual file systems
--------------------------------------------------

Zip and Tar archives can be treated as virtual filesystems and Collections can
be made from paths and layers within them. In other words, Fiona lets you read
and write zipped Shapefiles.

.. sourcecode:: python

for i, layername in enumerate(
fiona.listlayers(
'/',
vfs='zip://docs/data/test_uk.zip')):
with fiona.open(
'/',
vfs='zip://docs/data/test_uk.zip',
layer=i) as c:
print(i, layername, len(c))

# Output:
# 0 test_uk 48

Dumpgj
======

Expand Down
14 changes: 9 additions & 5 deletions src/fiona/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
ring of the polygon and using that as the point geometry for a new
feature writing to a "points.shp" file.
>>> from fiona import collection
>>> with collection("docs/data/test_uk.shp", "r") as inp:
>>> import fiona
>>> with fiona.open('docs/data/test_uk.shp', 'r') as inp:
... output_schema = inp.schema.copy()
... output_schema['geometry'] = 'Point'
... with collection(
Expand Down Expand Up @@ -72,11 +72,15 @@
from fiona.ogrext import _listlayers


def open(path, mode='r',
driver=None, schema=None, crs=None,
def open(
path,
mode='r',
driver=None,
schema=None,
crs=None,
encoding=None,
layer=None,
vfs=None):
vfs=None ):

"""Open file at ``path`` in ``mode`` "r" (read), "a" (append), or
"w" (write) and return a ``Collection`` object.
Expand Down
8 changes: 5 additions & 3 deletions src/fiona/ogrext.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,8 @@ cdef class Session:
path_c = path_b
self.cogr_ds = ograpi.OGROpen(path_c, 0, NULL)
if self.cogr_ds is NULL:
raise ValueError("Null data source")
raise ValueError(
"No data available at path '%s'" % collection.path)

if isinstance(collection.name, string_types):
name_b = collection.name.encode()
Expand All @@ -611,7 +612,8 @@ cdef class Session:
self._fileencoding = userencoding.upper()
else:
self._fileencoding = (
ograpi.OGR_L_TestCapability(self.cogr_layer, "StringsAsUTF8") and
ograpi.OGR_L_TestCapability(
self.cogr_layer, "StringsAsUTF8") and
OGR_DETECTED_ENCODING) or (
self.get_driver() == "ESRI Shapefile" and
'ISO-8859-1') or locale.getpreferredencoding().upper()
Expand Down Expand Up @@ -1016,7 +1018,7 @@ def _listlayers(path):
path_c = path_b
cogr_ds = ograpi.OGROpen(path_c, 0, NULL)
if cogr_ds is NULL:
raise ValueError("Null data source")
raise ValueError("No data available at path '%s'" % path)

# Loop over the layers to get their names.
layer_count = ograpi.OGR_DS_GetLayerCount(cogr_ds)
Expand Down
8 changes: 4 additions & 4 deletions tests/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def setUp(self):
'geometry': 'Point',
'properties': {'label': 'str', u'verit\xe9': 'int'} }
self.c = fiona.open(
"test-no-iter.shp",
"/tmp/test-no-iter.shp",
"w",
"ESRI Shapefile",
schema=schema,
Expand Down Expand Up @@ -387,9 +387,9 @@ def test_invalid_mode(self):
self.assertRaises(ValueError, fiona.open, "/tmp/bogus.shp", "r+")

def test_w_args(self):
self.assertRaises(FionaValueError, fiona.open, "test-no-iter.shp", "w")
self.assertRaises(FionaValueError, fiona.open, "/tmp/test-no-iter.shp", "w")
self.assertRaises(
FionaValueError, fiona.open, "test-no-iter.shp", "w", "Driver")
FionaValueError, fiona.open, "/tmp/test-no-iter.shp", "w", "Driver")

def test_no_path(self):
self.assertRaises(IOError, fiona.open, "no-path.shp", "a")
Expand All @@ -398,6 +398,6 @@ def test_no_read_conn_str(self):
self.assertRaises(IOError, fiona.open, "PG:dbname=databasename", "r")

def test_no_read_directory(self):
self.assertRaises(ValueError, fiona.open, ".", "r")
self.assertRaises(ValueError, fiona.open, "/dev/null", "r")


25 changes: 25 additions & 0 deletions tests/test_geojson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

import logging
import os
import shutil
import sys
import unittest

import fiona
from fiona.collection import supported_drivers
from fiona.errors import FionaValueError, DriverError, SchemaError, CRSError

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)


class ReadingTest(unittest.TestCase):

def setUp(self):
self.c = fiona.open('docs/data/test_uk.json', 'r')

def tearDown(self):
self.c.close()

def test_json(self):
self.assertEquals(len(self.c), 48)

0 comments on commit 6d9911b

Please sign in to comment.