Skip to content

Commit af1dee9

Browse files
committed
Fix errors when writing to individual file-handles, fix corresponding tests
Previous tests failed to detect the errors because the errors only happen when trying to add a record or shape; fixed. Files were not closed and thus did not flush the updated header data; fixed. Made sure shx records were only written if shx file was available.
1 parent ff51716 commit af1dee9

18 files changed

+111
-38
lines changed

shapefile.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -1861,14 +1861,13 @@ def close(self):
18611861
if self.dbf and dbf_open:
18621862
self.__dbfHeader()
18631863

1864-
# Close files, if target is a filepath
1865-
if self.target:
1866-
for attribute in (self.shp, self.shx, self.dbf):
1867-
if hasattr(attribute, 'close'):
1868-
try:
1869-
attribute.close()
1870-
except IOError:
1871-
pass
1864+
# Close files
1865+
for attribute in (self.shp, self.shx, self.dbf):
1866+
if hasattr(attribute, 'close'):
1867+
try:
1868+
attribute.close()
1869+
except IOError:
1870+
pass
18721871

18731872
def __getFileObj(self, f):
18741873
"""Safety handler to verify file-like objects"""
@@ -2088,7 +2087,8 @@ def shape(self, s):
20882087
"not: %r" % s)
20892088
# Write to file
20902089
offset,length = self.__shpRecord(s)
2091-
self.__shxRecord(offset, length)
2090+
if self.shx:
2091+
self.__shxRecord(offset, length)
20922092

20932093
def __shpRecord(self, s):
20942094
f = self.__getFileObj(self.shp)

shapefiles/test/balancing.dbf

0 Bytes
Binary file not shown.

shapefiles/test/contextwriter.dbf

0 Bytes
Binary file not shown.

shapefiles/test/corrupt_too_long.dbf

0 Bytes
Binary file not shown.

shapefiles/test/dtype.dbf

0 Bytes
Binary file not shown.

shapefiles/test/edit.dbf

0 Bytes
Binary file not shown.

shapefiles/test/line.dbf

0 Bytes
Binary file not shown.

shapefiles/test/linem.dbf

0 Bytes
Binary file not shown.

shapefiles/test/linez.dbf

0 Bytes
Binary file not shown.

shapefiles/test/merge.dbf

0 Bytes
Binary file not shown.

shapefiles/test/multipatch.dbf

0 Bytes
Binary file not shown.

shapefiles/test/multipoint.dbf

0 Bytes
Binary file not shown.

shapefiles/test/onlydbf.dbf

0 Bytes
Binary file not shown.

shapefiles/test/point.dbf

0 Bytes
Binary file not shown.

shapefiles/test/polygon.dbf

0 Bytes
Binary file not shown.

shapefiles/test/shapetype.dbf

0 Bytes
Binary file not shown.

shapefiles/test/testfile.dbf

0 Bytes
Binary file not shown.

test_shapefile.py

+102-29
Original file line numberDiff line numberDiff line change
@@ -1019,38 +1019,93 @@ def test_write_shp_only(tmpdir):
10191019
shp argument to the shapefile writer
10201020
creates just a shp file.
10211021
"""
1022-
filename = tmpdir.join("test.shp").strpath
1023-
with shapefile.Writer(shp=filename) as writer:
1024-
pass
1022+
filename = tmpdir.join("test").strpath
1023+
with shapefile.Writer(shp=open(filename+'.shp','wb')) as writer:
1024+
writer.point(1, 1)
1025+
assert writer.shp and not writer.shx and not writer.dbf
1026+
assert writer.shpNum == 1
1027+
assert len(writer) == 1
1028+
assert writer.shp.closed == True
10251029

10261030
# assert test.shp exists
1027-
assert os.path.exists(filename)
1031+
assert os.path.exists(filename+'.shp')
1032+
1033+
# test that can read shapes
1034+
with shapefile.Reader(shp=open(filename+'.shp','rb')) as reader:
1035+
assert reader.shp and not reader.shx and not reader.dbf
1036+
assert (reader.numRecords, reader.numShapes) == (None, None) # numShapes is unknown in the absence of shx file
1037+
assert len(reader.shapes()) == 1
10281038

10291039
# assert test.shx does not exist
1030-
assert not os.path.exists(tmpdir.join("test.shx").strpath)
1040+
assert not os.path.exists(filename+'.shx')
10311041

10321042
# assert test.dbf does not exist
1033-
assert not os.path.exists(tmpdir.join("test.dbf").strpath)
1043+
assert not os.path.exists(filename+'.dbf')
10341044

10351045

1036-
def test_write_shx_only(tmpdir):
1046+
def test_write_shp_shx_only(tmpdir):
10371047
"""
1038-
Assert that specifying just the
1048+
Assert that specifying just the shp and
10391049
shx argument to the shapefile writer
1040-
creates just a shx file.
1050+
creates just a shp and shx file.
10411051
"""
1042-
filename = tmpdir.join("test.shx").strpath
1043-
with shapefile.Writer(shx=filename) as writer:
1044-
pass
1052+
filename = tmpdir.join("test").strpath
1053+
with shapefile.Writer(shp=open(filename+'.shp','wb'), shx=open(filename+'.shx','wb')) as writer:
1054+
writer.point(1, 1)
1055+
assert writer.shp and writer.shx and not writer.dbf
1056+
assert writer.shpNum == 1
1057+
assert len(writer) == 1
1058+
assert writer.shp.closed == writer.shx.closed == True
1059+
1060+
# assert test.shp exists
1061+
assert os.path.exists(filename+'.shp')
10451062

10461063
# assert test.shx exists
1047-
assert os.path.exists(filename)
1064+
assert os.path.exists(filename+'.shx')
10481065

1049-
# assert test.shp does not exist
1050-
assert not os.path.exists(tmpdir.join("test.shp").strpath)
1066+
# test that can read shapes and offsets
1067+
with shapefile.Reader(shp=open(filename+'.shp','rb'), shx=open(filename+'.shx','rb')) as reader:
1068+
assert reader.shp and reader.shx and not reader.dbf
1069+
assert (reader.numRecords, reader.numShapes) == (None, 1)
1070+
reader.shape(0) # trigger reading of shx offsets
1071+
assert len(reader._offsets) == 1
1072+
assert len(reader.shapes()) == 1
10511073

10521074
# assert test.dbf does not exist
1053-
assert not os.path.exists(tmpdir.join("test.dbf").strpath)
1075+
assert not os.path.exists(filename+'.dbf')
1076+
1077+
1078+
def test_write_shp_dbf_only(tmpdir):
1079+
"""
1080+
Assert that specifying just the
1081+
shp and dbf argument to the shapefile writer
1082+
creates just a shp and dbf file.
1083+
"""
1084+
filename = tmpdir.join("test").strpath
1085+
with shapefile.Writer(shp=open(filename+'.shp','wb'), dbf=open(filename+'.dbf','wb')) as writer:
1086+
writer.field('field1', 'C') # required to create a valid dbf file
1087+
writer.record('value')
1088+
writer.point(1, 1)
1089+
assert writer.shp and not writer.shx and writer.dbf
1090+
assert writer.shpNum == writer.recNum == 1
1091+
assert len(writer) == 1
1092+
assert writer.shp.closed == writer.dbf.closed == True
1093+
1094+
# assert test.shp exists
1095+
assert os.path.exists(filename+'.shp')
1096+
1097+
# assert test.dbf exists
1098+
assert os.path.exists(filename+'.dbf')
1099+
1100+
# test that can read records and shapes
1101+
with shapefile.Reader(shp=open(filename+'.shp','rb'), dbf=open(filename+'.dbf','rb')) as reader:
1102+
assert reader.shp and not reader.shx and reader.dbf
1103+
assert (reader.numRecords, reader.numShapes) == (1, None) # numShapes is unknown in the absence of shx file
1104+
assert len(reader.records()) == 1
1105+
assert len(reader.shapes()) == 1
1106+
1107+
# assert test.shx does not exist
1108+
assert not os.path.exists(filename+'.shx')
10541109

10551110

10561111
def test_write_dbf_only(tmpdir):
@@ -1059,18 +1114,29 @@ def test_write_dbf_only(tmpdir):
10591114
dbf argument to the shapefile writer
10601115
creates just a dbf file.
10611116
"""
1062-
filename = tmpdir.join("test.dbf").strpath
1063-
with shapefile.Writer(dbf=filename) as writer:
1117+
filename = tmpdir.join("test").strpath
1118+
with shapefile.Writer(dbf=open(filename+'.dbf','wb')) as writer:
10641119
writer.field('field1', 'C') # required to create a valid dbf file
1120+
writer.record('value')
1121+
assert not writer.shp and not writer.shx and writer.dbf
1122+
assert writer.recNum == 1
1123+
assert len(writer) == 1
1124+
assert writer.dbf.closed == True
10651125

10661126
# assert test.dbf exists
1067-
assert os.path.exists(filename)
1127+
assert os.path.exists(filename+'.dbf')
1128+
1129+
# test that can read records
1130+
with shapefile.Reader(dbf=open(filename+'.dbf','rb')) as reader:
1131+
assert not writer.shp and not writer.shx and writer.dbf
1132+
assert (reader.numRecords, reader.numShapes) == (1, None)
1133+
assert len(reader.records()) == 1
10681134

10691135
# assert test.shp does not exist
1070-
assert not os.path.exists(tmpdir.join("test.shp").strpath)
1136+
assert not os.path.exists(filename+'.shp')
10711137

10721138
# assert test.shx does not exist
1073-
assert not os.path.exists(tmpdir.join("test.shx").strpath)
1139+
assert not os.path.exists(filename+'.shx')
10741140

10751141

10761142
def test_write_default_shp_shx_dbf(tmpdir):
@@ -1133,10 +1199,10 @@ def test_write_record(tmpdir):
11331199
with shapefile.Writer(filename) as writer:
11341200
writer.autoBalance = True
11351201

1136-
writer.field('one', 'C') # many under length limit
1137-
writer.field('two', 'C') # 1 under length limit
1138-
writer.field('three', 'C') # at length limit
1139-
writer.field('four', 'C') # 1 over length limit
1202+
writer.field('one', 'C')
1203+
writer.field('two', 'C')
1204+
writer.field('three', 'C')
1205+
writer.field('four', 'C')
11401206

11411207
values = ['one','two','three','four']
11421208
writer.record(*values)
@@ -1160,10 +1226,10 @@ def test_write_partial_record(tmpdir):
11601226
with shapefile.Writer(filename) as writer:
11611227
writer.autoBalance = True
11621228

1163-
writer.field('one', 'C') # many under length limit
1164-
writer.field('two', 'C') # 1 under length limit
1165-
writer.field('three', 'C') # at length limit
1166-
writer.field('four', 'C') # 1 over length limit
1229+
writer.field('one', 'C')
1230+
writer.field('two', 'C')
1231+
writer.field('three', 'C')
1232+
writer.field('four', 'C')
11671233

11681234
values = ['one','two']
11691235
writer.record(*values)
@@ -1220,4 +1286,11 @@ def test_write_empty_shapefile(tmpdir, shape_type):
12201286
w.field('field1', 'C') # required to create a valid dbf file
12211287

12221288
with shapefile.Reader(filename) as r:
1289+
# test correct shape type
12231290
assert r.shapeType == shape_type
1291+
# test length 0
1292+
assert len(r) == r.numRecords == r.numShapes == 0
1293+
# test records are empty
1294+
assert len(r.records()) == 0
1295+
# test shapes are empty
1296+
assert len(r.shapes()) == 0

0 commit comments

Comments
 (0)