Skip to content

Fix file-like objects without seek support not working #81

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions shapefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import array
import tempfile
import itertools
import io
from datetime import date

#
Expand Down Expand Up @@ -220,6 +221,12 @@ class Reader:
within each file is only accessed when required and as
efficiently as possible. Shapefiles are usually not large
but they can be.

If initializing the reader with a file-like object which
does not support seek(), you must set allow_copy=True
to allow the Reader to copy the entire file in memory.
This is set to False by default in order to avoid
large files being copyied into memory without user intention.
"""
def __init__(self, *args, **kwargs):
self.shp = None
Expand All @@ -231,6 +238,12 @@ def __init__(self, *args, **kwargs):
self.numRecords = None
self.fields = []
self.__dbfHdrLength = 0
# Allow in-memory copy (only if required)
# Even if allowed, this will only happen
# for files that do not support seek.
# False by default to avoid consuming huge amounts
# of memory
allow_copy = "allow_copy" in kwargs and kwargs["allow_copy"]
# See if a shapefile name was passed as an argument
if len(args) > 0:
if is_string(args[0]):
Expand All @@ -239,23 +252,47 @@ def __init__(self, *args, **kwargs):
if "shp" in kwargs.keys():
if hasattr(kwargs["shp"], "read"):
self.shp = kwargs["shp"]
if hasattr(self.shp, "seek"):
# Copy if required
try:
self.shp.seek(0)
except (NameError, io.UnsupportedOperation):
if allow_copy:
self.shp = io.BytesIO(self.shp.read())
else:
raise ValueError("shp argument does not "\
"support seek, consider allow_copy=True")
if "shx" in kwargs.keys():
if hasattr(kwargs["shx"], "read"):
self.shx = kwargs["shx"]
if hasattr(self.shx, "seek"):
# Copy if required
try:
self.shx.seek(0)
except (NameError, io.UnsupportedOperation):
if allow_copy:
self.shx = io.BytesIO(self.shx.read())
else:
raise ValueError("shx argument does not "\
"support seek, consider allow_copy=True")
if "dbf" in kwargs.keys():
if hasattr(kwargs["dbf"], "read"):
self.dbf = kwargs["dbf"]
if hasattr(self.dbf, "seek"):
# Copy if required
try:
self.dbf.seek(0)
except (NameError, io.UnsupportedOperation):
if allow_copy:
self.dbf = io.BytesIO(self.dbf.read())
else:
raise ValueError("dbf argument does not "\
"support seek, consider allow_copy=True")
if self.shp or self.dbf:
self.load()
else:
raise ShapefileException("Shapefile Reader requires a shapefile or file-like object.")




def load(self, shapefile=None):
"""Opens a shapefile from a filename or file-like
object. Normally this method would be called by the
Expand Down