diff --git a/shapefile.py b/shapefile.py index 0c665e0..797338e 100644 --- a/shapefile.py +++ b/shapefile.py @@ -1861,14 +1861,13 @@ def close(self): if self.dbf and dbf_open: self.__dbfHeader() - # Close files, if target is a filepath - if self.target: - for attribute in (self.shp, self.shx, self.dbf): - if hasattr(attribute, 'close'): - try: - attribute.close() - except IOError: - pass + # Close files + for attribute in (self.shp, self.shx, self.dbf): + if hasattr(attribute, 'close'): + try: + attribute.close() + except IOError: + pass def __getFileObj(self, f): """Safety handler to verify file-like objects""" @@ -2088,7 +2087,8 @@ def shape(self, s): "not: %r" % s) # Write to file offset,length = self.__shpRecord(s) - self.__shxRecord(offset, length) + if self.shx: + self.__shxRecord(offset, length) def __shpRecord(self, s): f = self.__getFileObj(self.shp) diff --git a/shapefiles/test/balancing.dbf b/shapefiles/test/balancing.dbf index 0da4a8d..62476f8 100644 Binary files a/shapefiles/test/balancing.dbf and b/shapefiles/test/balancing.dbf differ diff --git a/shapefiles/test/contextwriter.dbf b/shapefiles/test/contextwriter.dbf index 58e825d..ae080bf 100644 Binary files a/shapefiles/test/contextwriter.dbf and b/shapefiles/test/contextwriter.dbf differ diff --git a/shapefiles/test/corrupt_too_long.dbf b/shapefiles/test/corrupt_too_long.dbf index b92d438..0acc46a 100644 Binary files a/shapefiles/test/corrupt_too_long.dbf and b/shapefiles/test/corrupt_too_long.dbf differ diff --git a/shapefiles/test/dtype.dbf b/shapefiles/test/dtype.dbf index 3dafac7..ad798c4 100644 Binary files a/shapefiles/test/dtype.dbf and b/shapefiles/test/dtype.dbf differ diff --git a/shapefiles/test/edit.dbf b/shapefiles/test/edit.dbf index 7f6d890..bc95693 100644 Binary files a/shapefiles/test/edit.dbf and b/shapefiles/test/edit.dbf differ diff --git a/shapefiles/test/line.dbf b/shapefiles/test/line.dbf index 8ab0a1f..21802a0 100644 Binary files a/shapefiles/test/line.dbf and b/shapefiles/test/line.dbf differ diff --git a/shapefiles/test/linem.dbf b/shapefiles/test/linem.dbf index c34c495..aec663c 100644 Binary files a/shapefiles/test/linem.dbf and b/shapefiles/test/linem.dbf differ diff --git a/shapefiles/test/linez.dbf b/shapefiles/test/linez.dbf index df8b7f4..175ad0e 100644 Binary files a/shapefiles/test/linez.dbf and b/shapefiles/test/linez.dbf differ diff --git a/shapefiles/test/merge.dbf b/shapefiles/test/merge.dbf index 2d01d9d..a620dfd 100644 Binary files a/shapefiles/test/merge.dbf and b/shapefiles/test/merge.dbf differ diff --git a/shapefiles/test/multipatch.dbf b/shapefiles/test/multipatch.dbf index 619b94e..b2b05ca 100644 Binary files a/shapefiles/test/multipatch.dbf and b/shapefiles/test/multipatch.dbf differ diff --git a/shapefiles/test/multipoint.dbf b/shapefiles/test/multipoint.dbf index 6fb00c0..b7c57bf 100644 Binary files a/shapefiles/test/multipoint.dbf and b/shapefiles/test/multipoint.dbf differ diff --git a/shapefiles/test/onlydbf.dbf b/shapefiles/test/onlydbf.dbf index 58e825d..ae080bf 100644 Binary files a/shapefiles/test/onlydbf.dbf and b/shapefiles/test/onlydbf.dbf differ diff --git a/shapefiles/test/point.dbf b/shapefiles/test/point.dbf index db78fec..646e45b 100644 Binary files a/shapefiles/test/point.dbf and b/shapefiles/test/point.dbf differ diff --git a/shapefiles/test/polygon.dbf b/shapefiles/test/polygon.dbf index b64620c..bbad177 100644 Binary files a/shapefiles/test/polygon.dbf and b/shapefiles/test/polygon.dbf differ diff --git a/shapefiles/test/shapetype.dbf b/shapefiles/test/shapetype.dbf index 58e825d..ae080bf 100644 Binary files a/shapefiles/test/shapetype.dbf and b/shapefiles/test/shapetype.dbf differ diff --git a/shapefiles/test/testfile.dbf b/shapefiles/test/testfile.dbf index 58e825d..ae080bf 100644 Binary files a/shapefiles/test/testfile.dbf and b/shapefiles/test/testfile.dbf differ diff --git a/test_shapefile.py b/test_shapefile.py index 9bf5e29..95cd5a6 100644 --- a/test_shapefile.py +++ b/test_shapefile.py @@ -1019,38 +1019,93 @@ def test_write_shp_only(tmpdir): shp argument to the shapefile writer creates just a shp file. """ - filename = tmpdir.join("test.shp").strpath - with shapefile.Writer(shp=filename) as writer: - pass + filename = tmpdir.join("test").strpath + with shapefile.Writer(shp=open(filename+'.shp','wb')) as writer: + writer.point(1, 1) + assert writer.shp and not writer.shx and not writer.dbf + assert writer.shpNum == 1 + assert len(writer) == 1 + assert writer.shp.closed == True # assert test.shp exists - assert os.path.exists(filename) + assert os.path.exists(filename+'.shp') + + # test that can read shapes + with shapefile.Reader(shp=open(filename+'.shp','rb')) as reader: + assert reader.shp and not reader.shx and not reader.dbf + assert (reader.numRecords, reader.numShapes) == (None, None) # numShapes is unknown in the absence of shx file + assert len(reader.shapes()) == 1 # assert test.shx does not exist - assert not os.path.exists(tmpdir.join("test.shx").strpath) + assert not os.path.exists(filename+'.shx') # assert test.dbf does not exist - assert not os.path.exists(tmpdir.join("test.dbf").strpath) + assert not os.path.exists(filename+'.dbf') -def test_write_shx_only(tmpdir): +def test_write_shp_shx_only(tmpdir): """ - Assert that specifying just the + Assert that specifying just the shp and shx argument to the shapefile writer - creates just a shx file. + creates just a shp and shx file. """ - filename = tmpdir.join("test.shx").strpath - with shapefile.Writer(shx=filename) as writer: - pass + filename = tmpdir.join("test").strpath + with shapefile.Writer(shp=open(filename+'.shp','wb'), shx=open(filename+'.shx','wb')) as writer: + writer.point(1, 1) + assert writer.shp and writer.shx and not writer.dbf + assert writer.shpNum == 1 + assert len(writer) == 1 + assert writer.shp.closed == writer.shx.closed == True + + # assert test.shp exists + assert os.path.exists(filename+'.shp') # assert test.shx exists - assert os.path.exists(filename) + assert os.path.exists(filename+'.shx') - # assert test.shp does not exist - assert not os.path.exists(tmpdir.join("test.shp").strpath) + # test that can read shapes and offsets + with shapefile.Reader(shp=open(filename+'.shp','rb'), shx=open(filename+'.shx','rb')) as reader: + assert reader.shp and reader.shx and not reader.dbf + assert (reader.numRecords, reader.numShapes) == (None, 1) + reader.shape(0) # trigger reading of shx offsets + assert len(reader._offsets) == 1 + assert len(reader.shapes()) == 1 # assert test.dbf does not exist - assert not os.path.exists(tmpdir.join("test.dbf").strpath) + assert not os.path.exists(filename+'.dbf') + + +def test_write_shp_dbf_only(tmpdir): + """ + Assert that specifying just the + shp and dbf argument to the shapefile writer + creates just a shp and dbf file. + """ + filename = tmpdir.join("test").strpath + with shapefile.Writer(shp=open(filename+'.shp','wb'), dbf=open(filename+'.dbf','wb')) as writer: + writer.field('field1', 'C') # required to create a valid dbf file + writer.record('value') + writer.point(1, 1) + assert writer.shp and not writer.shx and writer.dbf + assert writer.shpNum == writer.recNum == 1 + assert len(writer) == 1 + assert writer.shp.closed == writer.dbf.closed == True + + # assert test.shp exists + assert os.path.exists(filename+'.shp') + + # assert test.dbf exists + assert os.path.exists(filename+'.dbf') + + # test that can read records and shapes + with shapefile.Reader(shp=open(filename+'.shp','rb'), dbf=open(filename+'.dbf','rb')) as reader: + assert reader.shp and not reader.shx and reader.dbf + assert (reader.numRecords, reader.numShapes) == (1, None) # numShapes is unknown in the absence of shx file + assert len(reader.records()) == 1 + assert len(reader.shapes()) == 1 + + # assert test.shx does not exist + assert not os.path.exists(filename+'.shx') def test_write_dbf_only(tmpdir): @@ -1059,18 +1114,29 @@ def test_write_dbf_only(tmpdir): dbf argument to the shapefile writer creates just a dbf file. """ - filename = tmpdir.join("test.dbf").strpath - with shapefile.Writer(dbf=filename) as writer: + filename = tmpdir.join("test").strpath + with shapefile.Writer(dbf=open(filename+'.dbf','wb')) as writer: writer.field('field1', 'C') # required to create a valid dbf file + writer.record('value') + assert not writer.shp and not writer.shx and writer.dbf + assert writer.recNum == 1 + assert len(writer) == 1 + assert writer.dbf.closed == True # assert test.dbf exists - assert os.path.exists(filename) + assert os.path.exists(filename+'.dbf') + + # test that can read records + with shapefile.Reader(dbf=open(filename+'.dbf','rb')) as reader: + assert not writer.shp and not writer.shx and writer.dbf + assert (reader.numRecords, reader.numShapes) == (1, None) + assert len(reader.records()) == 1 # assert test.shp does not exist - assert not os.path.exists(tmpdir.join("test.shp").strpath) + assert not os.path.exists(filename+'.shp') # assert test.shx does not exist - assert not os.path.exists(tmpdir.join("test.shx").strpath) + assert not os.path.exists(filename+'.shx') def test_write_default_shp_shx_dbf(tmpdir): @@ -1133,10 +1199,10 @@ def test_write_record(tmpdir): with shapefile.Writer(filename) as writer: writer.autoBalance = True - writer.field('one', 'C') # many under length limit - writer.field('two', 'C') # 1 under length limit - writer.field('three', 'C') # at length limit - writer.field('four', 'C') # 1 over length limit + writer.field('one', 'C') + writer.field('two', 'C') + writer.field('three', 'C') + writer.field('four', 'C') values = ['one','two','three','four'] writer.record(*values) @@ -1160,10 +1226,10 @@ def test_write_partial_record(tmpdir): with shapefile.Writer(filename) as writer: writer.autoBalance = True - writer.field('one', 'C') # many under length limit - writer.field('two', 'C') # 1 under length limit - writer.field('three', 'C') # at length limit - writer.field('four', 'C') # 1 over length limit + writer.field('one', 'C') + writer.field('two', 'C') + writer.field('three', 'C') + writer.field('four', 'C') values = ['one','two'] writer.record(*values) @@ -1220,4 +1286,11 @@ def test_write_empty_shapefile(tmpdir, shape_type): w.field('field1', 'C') # required to create a valid dbf file with shapefile.Reader(filename) as r: + # test correct shape type assert r.shapeType == shape_type + # test length 0 + assert len(r) == r.numRecords == r.numShapes == 0 + # test records are empty + assert len(r.records()) == 0 + # test shapes are empty + assert len(r.shapes()) == 0