Skip to content

Added improvements for date field inputs #31

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
wants to merge 2 commits into from
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
40 changes: 27 additions & 13 deletions shapefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import array
import tempfile
import itertools
import datetime
import re

#
# Constants for shape types
Expand All @@ -36,10 +38,12 @@
MULTIPATCH = 31

PYTHON3 = sys.version_info[0] == 3
DATE_EXP = re.compile('\d{4}[-/]\d{2}[-/]\d{2}')

if PYTHON3:
xrange = range
izip = zip
basestring = str
else:
from itertools import izip

Expand Down Expand Up @@ -209,10 +213,8 @@ class Reader:
but is not required to read the geometry from the .shp
file. The "shapefile" argument in the constructor is the
name of the file you want to open.

You can instantiate a Reader without specifying a shapefile
and then specify one later with the load() method.

Only the shapefile headers are read upon loading. Content
within each file is only accessed when required and as
efficiently as possible. Shapefiles are usually not large
Expand Down Expand Up @@ -248,7 +250,7 @@ def __init__(self, *args, **kwargs):
self.dbf = kwargs["dbf"]
if hasattr(self.dbf, "seek"):
self.dbf.seek(0)
if self.shp or self.dbf:
if self.shp or self.dbf:
self.load()
else:
raise ShapefileException("Shapefile Reader requires a shapefile or file-like object.")
Expand Down Expand Up @@ -373,7 +375,7 @@ def __shape(self):
record.m = unpack("<d", f.read(8))
# Seek to the end of this record as defined by the record header because
# the shapefile spec doesn't require the actual content to meet the header
# definition. Probably allowed for lazy feature deletion.
# definition. Probably allowed for lazy feature deletion.
f.seek(next)
return record

Expand Down Expand Up @@ -434,7 +436,7 @@ def iterShapes(self):
self.shpLength = shp.tell()
shp.seek(100)
while shp.tell() < self.shpLength:
yield self.__shape()
yield self.__shape()

def __dbfHeaderLength(self):
"""Retrieves the header length of a dbf file header."""
Expand Down Expand Up @@ -828,7 +830,7 @@ def __shpRecords(self):
if hasattr(s,"z"):
f.write(pack("<%sd" % len(s.z), *s.z))
else:
[f.write(pack("<d", p[2])) for p in s.points]
[f.write(pack("<d", p[2])) for p in s.points]
except error:
raise ShapefileException("Failed to write elevation values for record %s. Expected floats." % recNum)
# Write m extremes and values
Expand All @@ -855,7 +857,7 @@ def __shpRecords(self):
if hasattr(s, "z"):
try:
if not s.z:
s.z = (0,)
s.z = (0,)
f.write(pack("<d", s.z[0]))
except error:
raise ShapefileException("Failed to write elevation value for record %s. Expected floats." % recNum)
Expand All @@ -871,11 +873,11 @@ def __shpRecords(self):
if hasattr(s, "m"):
try:
if not s.m:
s.m = (0,)
s.m = (0,)
f.write(pack("<1d", s.m[0]))
except error:
raise ShapefileException("Failed to write measure value for record %s. Expected floats." % recNum)
else:
raise ShapefileException("Failed to write measure value for record %s. Expected floats." % recNum)
else:
try:
if len(s.points[0])<4:
s.points[0].append(0)
Expand Down Expand Up @@ -912,6 +914,17 @@ def __dbfRecords(self):
value = str(value).rjust(size)
elif fieldType == 'L':
value = str(value)[0].upper()
elif fieldType == 'D':
if isinstance(value, datetime.datetime):
value = ''.join([str(v).zfill(2) for v in [value.year, value.month, value.day]])[:size].ljust(size)
elif isinstance(value, basestring):
if DATE_EXP.match(value):
try:
value = DATE_EXP.findall(value)[0].replace('/','').replace('-','')[:size].ljust(size)
except IndexError:
value = str(value)[:size].ljust(size)
else:
value = str(value)[:size].ljust(size)
else:
value = str(value)[:size].ljust(size)
if len(value) != size:
Expand Down Expand Up @@ -1038,8 +1051,8 @@ def save(self, target=None, shp=None, shx=None, dbf=None):
be written exclusively using saveShp, saveShx, and saveDbf respectively.
If target is specified but not shp,shx, or dbf then the target path and
file name are used. If no options or specified, a unique base file name
is generated to save the files and the base file name is returned as a
string.
is generated to save the files and the base file name is returned as a
string.
"""
# Create a unique file name if one is not defined
if shp:
Expand All @@ -1053,7 +1066,7 @@ def save(self, target=None, shp=None, shx=None, dbf=None):
if not target:
temp = tempfile.NamedTemporaryFile(prefix="shapefile_",dir=os.getcwd())
target = temp.name
generated = True
generated = True
self.saveShp(target)
self.shp.close()
self.saveShx(target)
Expand Down Expand Up @@ -1193,3 +1206,4 @@ def test():
2.3.
"""
test()