[Git][debian-gis-team/pyshp][upstream] New upstream version 2.3.1
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Thu Jul 28 04:32:20 BST 2022
Bas Couwenberg pushed to branch upstream at Debian GIS Project / pyshp
Commits:
fb4a6705 by Bas Couwenberg at 2022-07-28T05:16:48+02:00
New upstream version 2.3.1
- - - - -
25 changed files:
- + .github/ISSUE_TEMPLATE/bug.yml
- + .github/ISSUE_TEMPLATE/config.yml
- + .github/ISSUE_TEMPLATE/newfeature.yml
- + .github/ISSUE_TEMPLATE/question.yml
- + .github/ISSUE_TEMPLATE/unexpected.yml
- README.md
- changelog.txt
- shapefile.py
- shapefiles/test/balancing.dbf
- shapefiles/test/contextwriter.dbf
- shapefiles/test/corrupt_too_long.dbf
- shapefiles/test/dtype.dbf
- shapefiles/test/edit.dbf
- shapefiles/test/line.dbf
- shapefiles/test/linem.dbf
- shapefiles/test/linez.dbf
- shapefiles/test/merge.dbf
- shapefiles/test/multipatch.dbf
- shapefiles/test/multipoint.dbf
- shapefiles/test/onlydbf.dbf
- shapefiles/test/point.dbf
- shapefiles/test/polygon.dbf
- shapefiles/test/shapetype.dbf
- shapefiles/test/testfile.dbf
- test_shapefile.py
Changes:
=====================================
.github/ISSUE_TEMPLATE/bug.yml
=====================================
@@ -0,0 +1,47 @@
+name: Bug Report
+description: Something in PyShp crashed and raised an exception.
+title: "Title goes here..."
+labels: ["bug"]
+body:
+ - type: input
+ id: pyshp-version
+ attributes:
+ label: PyShp Version
+ description: Please input the version of PyShp you used. If unsure, call `shapefile.__version__`.
+ placeholder: ...
+ validations:
+ required: true
+ - type: input
+ id: python-version
+ attributes:
+ label: Python Version
+ description: Please input the version of the Python executable.
+ placeholder: ...
+ validations:
+ required: true
+ - type: textarea
+ id: your-code
+ attributes:
+ label: Your code
+ description: Please copy-paste the relevant parts of your code or script that triggered the error.
+ placeholder: ...
+ render: shell
+ validations:
+ required: true
+ - type: textarea
+ id: stacktrace
+ attributes:
+ label: Full stacktrace
+ description: Please copy-paste the full stack trace of the exception that was raised.
+ placeholder: ...
+ render: shell
+ validations:
+ required: true
+ - type: textarea
+ id: notes
+ attributes:
+ label: Other notes
+ description: Please input any other notes that may be relevant, e.g. do you have any thoughts on what might be wrong?
+ placeholder: ...
+ validations:
+ required: false
\ No newline at end of file
=====================================
.github/ISSUE_TEMPLATE/config.yml
=====================================
@@ -0,0 +1 @@
+blank_issues_enabled: true
\ No newline at end of file
=====================================
.github/ISSUE_TEMPLATE/newfeature.yml
=====================================
@@ -0,0 +1,21 @@
+name: Feature Request
+description: You would like to request a new feature.
+title: "Title goes here..."
+labels: ["enhancement"]
+body:
+ - type: textarea
+ id: functionality
+ attributes:
+ label: Describe the feature request
+ description: Please describe the functionality you would like added to PyShp.
+ placeholder: ...
+ validations:
+ required: true
+ - type: checkboxes
+ id: contribute
+ attributes:
+ label: Contributions
+ description: Would you be interested to contribute code that adds this functionality through a Pull Request? We gladly accept PRs - it's much faster and you'll be added a contributor.
+ options:
+ - label: I am interested in implementing the described feature request and submit as a PR.
+ required: false
\ No newline at end of file
=====================================
.github/ISSUE_TEMPLATE/question.yml
=====================================
@@ -0,0 +1,13 @@
+name: Question
+description: You have a question about PyShp or how to use it.
+title: "Title goes here..."
+labels: ["question"]
+body:
+ - type: textarea
+ id: question
+ attributes:
+ label: What's your question?
+ description: Please describe what you would like to know about PyShp, e.g. how to do something.
+ placeholder: ...
+ validations:
+ required: true
\ No newline at end of file
=====================================
.github/ISSUE_TEMPLATE/unexpected.yml
=====================================
@@ -0,0 +1,54 @@
+name: Unexpected Behavior
+description: You think PyShp might be doing something wrong.
+title: "Title goes here..."
+labels: ["bug"]
+body:
+ - type: input
+ id: pyshp-version
+ attributes:
+ label: PyShp Version
+ description: Please input the version of PyShp you used. If unsure, call `shapefile.__version__`.
+ placeholder: ...
+ validations:
+ required: true
+ - type: input
+ id: python-version
+ attributes:
+ label: Python Version
+ description: Please input the version of the Python executable.
+ placeholder: ...
+ validations:
+ required: true
+ - type: textarea
+ id: your-code
+ attributes:
+ label: Your code
+ description: Please copy-paste the relevant parts of your code or script that you tried to run.
+ placeholder: ...
+ render: shell
+ validations:
+ required: true
+ - type: textarea
+ id: expected-results
+ attributes:
+ label: Expected results
+ description: Please describe what you expected to see in the output.
+ placeholder: ...
+ validations:
+ required: true
+ - type: textarea
+ id: actual-results
+ attributes:
+ label: Actual results
+ description: Please describe what you actually saw in the output.
+ placeholder: ...
+ validations:
+ required: true
+ - type: textarea
+ id: notes
+ attributes:
+ label: Other notes
+ description: Please input any other notes that may be relevant, e.g. do you have any thoughts on what might be wrong?
+ placeholder: ...
+ validations:
+ required: false
\ No newline at end of file
=====================================
README.md
=====================================
@@ -95,6 +95,12 @@ part of your geospatial project.
# Version Changes
+## 2.3.1
+
+### Bug fixes:
+
+- Fix recently introduced issue where Reader/Writer closes file-like objects provided by user (#244)
+
## 2.3.0
### New Features:
@@ -722,7 +728,18 @@ write to them:
>>> w.record()
>>> w.null()
>>> w.close()
+
>>> # To read back the files you could call the "StringIO.getvalue()" method later.
+ >>> assert shp.getvalue()
+ >>> assert shx.getvalue()
+ >>> assert dbf.getvalue()
+
+ >>> # In fact, you can read directly from them using the Reader
+ >>> r = shapefile.Reader(shp=shp, shx=shx, dbf=dbf)
+ >>> len(r)
+ 1
+
+
#### Writing Shapefiles Using the Context Manager
@@ -1391,14 +1408,25 @@ ESRI White Paper](http://downloads.esri.com/support/whitepapers/ao_/J9749_MultiP
# Testing
-The testing framework is doctest, which are located in this file README.md.
+The testing framework is pytest, and the tests are located in test_shapefile.py.
+This includes an extensive set of unit tests of the various pyshp features,
+and tests against various input data. Some of the tests that require
+internet connectivity will be skipped in offline testing environments.
+In the same folder as README.md and shapefile.py, from the command line run
+```
+$ python -m pytest
+```
+
+Additionally, all the code and examples located in this file, README.md,
+is tested and verified with the builtin doctest framework.
+A special routine for invoking the doctest is run when calling directly on shapefile.py.
In the same folder as README.md and shapefile.py, from the command line run
```
$ python shapefile.py
```
Linux/Mac and similar platforms will need to run `$ dos2unix README.md` in order
-correct line endings in README.md.
+to correct line endings in README.md.
# Contributors
=====================================
changelog.txt
=====================================
@@ -1,4 +1,10 @@
+VERSION 2.3.1
+
+2022-07-28
+ Bug fixes:
+ * Fix recently introduced issue where Reader/Writer closes file-like objects provided by user (#244)
+
VERSION 2.3.0
2022-04-30
=====================================
shapefile.py
=====================================
@@ -6,7 +6,7 @@ maintainer: karim.bahgat.norway<at>gmail.com
Compatible with Python versions 2.7-3.x
"""
-__version__ = "2.3.0"
+__version__ = "2.3.1"
from struct import pack, unpack, calcsize, error, Struct
import os
@@ -932,6 +932,7 @@ class Reader(object):
self.shp = None
self.shx = None
self.dbf = None
+ self._files_to_close = []
self.shapeName = "Not specified"
self._offsets = []
self.shpLength = None
@@ -998,6 +999,7 @@ class Reader(object):
fileobj.write(member.read())
fileobj.seek(0)
setattr(self, ext, fileobj)
+ self._files_to_close.append(fileobj)
except:
pass
# Close and delete the temporary zipfile
@@ -1030,6 +1032,7 @@ class Reader(object):
fileobj.write(resp.read())
fileobj.seek(0)
setattr(self, ext, fileobj)
+ self._files_to_close.append(fileobj)
except HTTPError:
pass
if (self.shp or self.dbf):
@@ -1202,9 +1205,11 @@ class Reader(object):
shp_ext = 'shp'
try:
self.shp = open("%s.%s" % (shapefile_name, shp_ext), "rb")
+ self._files_to_close.append(self.shp)
except IOError:
try:
self.shp = open("%s.%s" % (shapefile_name, shp_ext.upper()), "rb")
+ self._files_to_close.append(self.shp)
except IOError:
pass
@@ -1215,9 +1220,11 @@ class Reader(object):
shx_ext = 'shx'
try:
self.shx = open("%s.%s" % (shapefile_name, shx_ext), "rb")
+ self._files_to_close.append(self.shx)
except IOError:
try:
self.shx = open("%s.%s" % (shapefile_name, shx_ext.upper()), "rb")
+ self._files_to_close.append(self.shx)
except IOError:
pass
@@ -1228,9 +1235,11 @@ class Reader(object):
dbf_ext = 'dbf'
try:
self.dbf = open("%s.%s" % (shapefile_name, dbf_ext), "rb")
+ self._files_to_close.append(self.dbf)
except IOError:
try:
self.dbf = open("%s.%s" % (shapefile_name, dbf_ext.upper()), "rb")
+ self._files_to_close.append(self.dbf)
except IOError:
pass
@@ -1238,18 +1247,14 @@ class Reader(object):
self.close()
def close(self):
- for attribute in ('shp','shx','dbf'):
- try:
- obj = getattr(self, attribute)
- except AttributeError:
- # deepcopies fail to copy these attributes and raises exception during
- # garbage collection - https://github.com/mattijn/topojson/issues/120
- obj = None
- if obj and hasattr(obj, 'close'):
+ # Close any files that the reader opened (but not those given by user)
+ for attribute in self._files_to_close:
+ if hasattr(attribute, 'close'):
try:
- obj.close()
+ attribute.close()
except IOError:
pass
+ self._files_to_close = []
def __getFileObj(self, f):
"""Checks to see if the requested shapefile file object is
@@ -1786,6 +1791,7 @@ class Writer(object):
self.fields = []
self.shapeType = shapeType
self.shp = self.shx = self.dbf = None
+ self._files_to_close = []
if target:
target = pathlike_obj(target)
if not is_string(target):
@@ -1866,13 +1872,22 @@ class Writer(object):
if self.dbf and dbf_open:
self.__dbfHeader()
- # Close files
+ # Flush files
for attribute in (self.shp, self.shx, self.dbf):
+ if hasattr(attribute, 'flush') and not (hasattr(attribute, 'closed') and attribute.closed):
+ try:
+ attribute.flush()
+ except IOError:
+ pass
+
+ # Close any files that the writer opened (but not those given by user)
+ for attribute in self._files_to_close:
if hasattr(attribute, 'close'):
try:
attribute.close()
except IOError:
pass
+ self._files_to_close = []
def __getFileObj(self, f):
"""Safety handler to verify file-like objects"""
@@ -1884,7 +1899,9 @@ class Writer(object):
pth = os.path.split(f)[0]
if pth and not os.path.exists(pth):
os.makedirs(pth)
- return open(f, "wb+")
+ fp = open(f, "wb+")
+ self._files_to_close.append(fp)
+ return fp
def __shpFileLength(self):
"""Calculates the file length of the shp file."""
=====================================
shapefiles/test/balancing.dbf
=====================================
Binary files a/shapefiles/test/balancing.dbf and b/shapefiles/test/balancing.dbf differ
=====================================
shapefiles/test/contextwriter.dbf
=====================================
Binary files a/shapefiles/test/contextwriter.dbf and b/shapefiles/test/contextwriter.dbf differ
=====================================
shapefiles/test/corrupt_too_long.dbf
=====================================
Binary files a/shapefiles/test/corrupt_too_long.dbf and b/shapefiles/test/corrupt_too_long.dbf differ
=====================================
shapefiles/test/dtype.dbf
=====================================
Binary files a/shapefiles/test/dtype.dbf and b/shapefiles/test/dtype.dbf differ
=====================================
shapefiles/test/edit.dbf
=====================================
Binary files a/shapefiles/test/edit.dbf and b/shapefiles/test/edit.dbf differ
=====================================
shapefiles/test/line.dbf
=====================================
Binary files a/shapefiles/test/line.dbf and b/shapefiles/test/line.dbf differ
=====================================
shapefiles/test/linem.dbf
=====================================
Binary files a/shapefiles/test/linem.dbf and b/shapefiles/test/linem.dbf differ
=====================================
shapefiles/test/linez.dbf
=====================================
Binary files a/shapefiles/test/linez.dbf and b/shapefiles/test/linez.dbf differ
=====================================
shapefiles/test/merge.dbf
=====================================
Binary files a/shapefiles/test/merge.dbf and b/shapefiles/test/merge.dbf differ
=====================================
shapefiles/test/multipatch.dbf
=====================================
Binary files a/shapefiles/test/multipatch.dbf and b/shapefiles/test/multipatch.dbf differ
=====================================
shapefiles/test/multipoint.dbf
=====================================
Binary files a/shapefiles/test/multipoint.dbf and b/shapefiles/test/multipoint.dbf differ
=====================================
shapefiles/test/onlydbf.dbf
=====================================
Binary files a/shapefiles/test/onlydbf.dbf and b/shapefiles/test/onlydbf.dbf differ
=====================================
shapefiles/test/point.dbf
=====================================
Binary files a/shapefiles/test/point.dbf and b/shapefiles/test/point.dbf differ
=====================================
shapefiles/test/polygon.dbf
=====================================
Binary files a/shapefiles/test/polygon.dbf and b/shapefiles/test/polygon.dbf differ
=====================================
shapefiles/test/shapetype.dbf
=====================================
Binary files a/shapefiles/test/shapetype.dbf and b/shapefiles/test/shapetype.dbf differ
=====================================
shapefiles/test/testfile.dbf
=====================================
Binary files a/shapefiles/test/testfile.dbf and b/shapefiles/test/testfile.dbf differ
=====================================
test_shapefile.py
=====================================
@@ -248,22 +248,6 @@ def test_shaperecord_geo_interface():
assert json.dumps(shaperec.__geo_interface__)
-def test_reader_context_manager():
- """
- Assert that the Reader context manager
- closes the shp, shx, and dbf files
- on exit.
- """
- # note uses an actual shapefile from
- # the projects "shapefiles" directory
- with shapefile.Reader("shapefiles/blockgroups") as sf:
- pass
-
- assert sf.shp.closed is True
- assert sf.dbf.closed is True
- assert sf.shx.closed is True
-
-
@pytest.mark.network
def test_reader_url():
"""
@@ -274,6 +258,7 @@ def test_reader_url():
with shapefile.Reader(url) as sf:
for recShape in sf.iterShapeRecords():
pass
+ assert sf.shp.closed == sf.shx.closed == sf.dbf.closed == True
# test without extension
url = "https://github.com/nvkelso/natural-earth-vector/blob/master/110m_cultural/ne_110m_admin_0_tiny_countries?raw=true"
@@ -281,6 +266,7 @@ def test_reader_url():
for recShape in sf.iterShapeRecords():
pass
assert len(sf) > 0
+ assert sf.shp.closed == sf.shx.closed == sf.dbf.closed == True
# test no files found
url = "https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/README.md"
@@ -294,6 +280,7 @@ def test_reader_url():
for recShape in sf.iterShapeRecords():
pass
assert len(sf) > 0
+ assert sf.shp.closed == sf.shx.closed == sf.dbf.closed == True
def test_reader_zip():
@@ -305,6 +292,7 @@ def test_reader_zip():
for recShape in sf.iterShapeRecords():
pass
assert len(sf) > 0
+ assert sf.shp.closed == sf.shx.closed == sf.dbf.closed == True
# test require specific path when reading multi-shapefile zipfile
with pytest.raises(shapefile.ShapefileException):
@@ -316,12 +304,14 @@ def test_reader_zip():
for recShape in sf.iterShapeRecords():
pass
assert len(sf) > 0
+ assert sf.shp.closed == sf.shx.closed == sf.dbf.closed == True
# test specifying the path when reading multi-shapefile zipfile (without extension)
with shapefile.Reader("shapefiles/blockgroups_multishapefile.zip/blockgroups2") as sf:
for recShape in sf.iterShapeRecords():
pass
assert len(sf) > 0
+ assert sf.shp.closed == sf.shx.closed == sf.dbf.closed == True
# test raising error when can't find shapefile inside zipfile
with pytest.raises(shapefile.ShapefileException):
@@ -329,11 +319,54 @@ def test_reader_zip():
pass
-def test_reader_close():
+def test_reader_close_path():
"""
Assert that manually calling Reader.close()
closes the shp, shx, and dbf files
- on exit.
+ on exit, if given paths.
+ """
+ # note uses an actual shapefile from
+ # the projects "shapefiles" directory
+ sf = shapefile.Reader("shapefiles/blockgroups.shp")
+ sf.close()
+
+ assert sf.shp.closed is True
+ assert sf.dbf.closed is True
+ assert sf.shx.closed is True
+
+ # check that can read again
+ sf = shapefile.Reader("shapefiles/blockgroups.shp")
+ sf.close()
+
+
+def test_reader_close_filelike():
+ """
+ Assert that manually calling Reader.close()
+ leaves the shp, shx, and dbf files open
+ on exit, if given filelike objects.
+ """
+ # note uses an actual shapefile from
+ # the projects "shapefiles" directory
+ shp = open("shapefiles/blockgroups.shp", mode='rb')
+ shx = open("shapefiles/blockgroups.shx", mode='rb')
+ dbf = open("shapefiles/blockgroups.dbf", mode='rb')
+ sf = shapefile.Reader(shp=shp, shx=shx, dbf=dbf)
+ sf.close()
+
+ assert sf.shp.closed is False
+ assert sf.dbf.closed is False
+ assert sf.shx.closed is False
+
+ # check that can read again
+ sf = shapefile.Reader(shp=shp, shx=shx, dbf=dbf)
+ sf.close()
+
+
+def test_reader_context_path():
+ """
+ Assert that using the context manager
+ closes the shp, shx, and dbf files
+ on exit, if given paths.
"""
# note uses an actual shapefile from
# the projects "shapefiles" directory
@@ -344,6 +377,33 @@ def test_reader_close():
assert sf.dbf.closed is True
assert sf.shx.closed is True
+ # check that can read again
+ with shapefile.Reader("shapefiles/blockgroups") as sf:
+ pass
+
+
+def test_reader_context_filelike():
+ """
+ Assert that using the context manager
+ leaves the shp, shx, and dbf files open
+ on exit, if given filelike objects.
+ """
+ # note uses an actual shapefile from
+ # the projects "shapefiles" directory
+ shp = open("shapefiles/blockgroups.shp", mode='rb')
+ shx = open("shapefiles/blockgroups.shx", mode='rb')
+ dbf = open("shapefiles/blockgroups.dbf", mode='rb')
+ with shapefile.Reader(shp=shp, shx=shx, dbf=dbf) as sf:
+ pass
+
+ assert sf.shp.closed is False
+ assert sf.dbf.closed is False
+ assert sf.shx.closed is False
+
+ # check that can read again
+ with shapefile.Reader(shp=shp, shx=shx, dbf=dbf) as sf:
+ pass
+
def test_reader_shapefile_type():
"""
@@ -1084,7 +1144,7 @@ def test_write_shp_only(tmpdir):
creates just a shp file.
"""
filename = tmpdir.join("test").strpath
- with shapefile.Writer(shp=open(filename+'.shp','wb')) as writer:
+ with shapefile.Writer(shp=filename+'.shp') as writer:
writer.point(1, 1)
assert writer.shp and not writer.shx and not writer.dbf
assert writer.shpNum == 1
@@ -1095,7 +1155,7 @@ def test_write_shp_only(tmpdir):
assert os.path.exists(filename+'.shp')
# test that can read shapes
- with shapefile.Reader(shp=open(filename+'.shp','rb')) as reader:
+ with shapefile.Reader(shp=filename+'.shp') 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
@@ -1114,7 +1174,7 @@ def test_write_shp_shx_only(tmpdir):
creates just a shp and shx file.
"""
filename = tmpdir.join("test").strpath
- with shapefile.Writer(shp=open(filename+'.shp','wb'), shx=open(filename+'.shx','wb')) as writer:
+ with shapefile.Writer(shp=filename+'.shp', shx=filename+'.shx') as writer:
writer.point(1, 1)
assert writer.shp and writer.shx and not writer.dbf
assert writer.shpNum == 1
@@ -1128,7 +1188,7 @@ def test_write_shp_shx_only(tmpdir):
assert os.path.exists(filename+'.shx')
# test that can read shapes and offsets
- with shapefile.Reader(shp=open(filename+'.shp','rb'), shx=open(filename+'.shx','rb')) as reader:
+ with shapefile.Reader(shp=filename+'.shp', shx=filename+'.shx') 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
@@ -1146,7 +1206,7 @@ def test_write_shp_dbf_only(tmpdir):
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:
+ with shapefile.Writer(shp=filename+'.shp', dbf=filename+'.dbf') as writer:
writer.field('field1', 'C') # required to create a valid dbf file
writer.record('value')
writer.point(1, 1)
@@ -1162,7 +1222,7 @@ def test_write_shp_dbf_only(tmpdir):
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:
+ with shapefile.Reader(shp=filename+'.shp', dbf=filename+'.dbf') 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
@@ -1179,7 +1239,7 @@ def test_write_dbf_only(tmpdir):
creates just a dbf file.
"""
filename = tmpdir.join("test").strpath
- with shapefile.Writer(dbf=open(filename+'.dbf','wb')) as writer:
+ with shapefile.Writer(dbf=filename+'.dbf') 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
@@ -1191,7 +1251,7 @@ def test_write_dbf_only(tmpdir):
assert os.path.exists(filename+'.dbf')
# test that can read records
- with shapefile.Reader(dbf=open(filename+'.dbf','rb')) as reader:
+ with shapefile.Reader(dbf=filename+'.dbf') 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
@@ -1212,6 +1272,8 @@ def test_write_default_shp_shx_dbf(tmpdir):
filename = tmpdir.join("test").strpath
with shapefile.Writer(filename) as writer:
writer.field('field1', 'C') # required to create a valid dbf file
+ writer.record('value')
+ writer.null()
# assert shp, shx, dbf files exist
assert os.path.exists(filename + ".shp")
@@ -1228,11 +1290,123 @@ def test_write_pathlike(tmpdir):
assert not isinstance(filename, str)
with shapefile.Writer(filename) as writer:
writer.field('field1', 'C')
+ writer.record('value')
+ writer.null()
assert (filename + ".shp").ensure()
assert (filename + ".shx").ensure()
assert (filename + ".dbf").ensure()
+def test_write_filelike(tmpdir):
+ """
+ Assert that file-like objects are written correctly.
+ """
+ shp = open(tmpdir.join("test.shp").strpath, mode='wb+')
+ shx = open(tmpdir.join("test.shx").strpath, mode='wb+')
+ dbf = open(tmpdir.join("test.dbf").strpath, mode='wb+')
+ with shapefile.Writer(shx=shx, dbf=dbf, shp=shp) as writer:
+ writer.field('field1', 'C') # required to create a valid dbf file
+ writer.record('value')
+ writer.null()
+
+ # test that filelike objects were written correctly
+ with shapefile.Reader(shp=shp, shx=shx, dbf=dbf) as reader:
+ assert len(reader) == 1
+ assert reader.shape(0).shapeType == shapefile.NULL
+
+
+def test_write_close_path(tmpdir):
+ """
+ Assert that the Writer close() method
+ closes the shp, shx, and dbf files
+ on exit, if given paths.
+ """
+ sf = shapefile.Writer(tmpdir.join('test'))
+ sf.field('field1', 'C') # required to create a valid dbf file
+ sf.record('value')
+ sf.null()
+ sf.close()
+
+ assert sf.shp.closed is True
+ assert sf.dbf.closed is True
+ assert sf.shx.closed is True
+
+ # test that opens and reads correctly after
+ with shapefile.Reader(tmpdir.join('test')) as reader:
+ assert len(reader) == 1
+ assert reader.shape(0).shapeType == shapefile.NULL
+
+
+def test_write_close_filelike(tmpdir):
+ """
+ Assert that the Writer close() method
+ leaves the shp, shx, and dbf files open
+ on exit, if given filelike objects.
+ """
+ shp = open(tmpdir.join("test.shp").strpath, mode='wb+')
+ shx = open(tmpdir.join("test.shx").strpath, mode='wb+')
+ dbf = open(tmpdir.join("test.dbf").strpath, mode='wb+')
+ sf = shapefile.Writer(shx=shx, dbf=dbf, shp=shp)
+ sf.field('field1', 'C') # required to create a valid dbf file
+ sf.record('value')
+ sf.null()
+ sf.close()
+
+ assert sf.shp.closed is False
+ assert sf.dbf.closed is False
+ assert sf.shx.closed is False
+
+ # test that opens and reads correctly after
+ with shapefile.Reader(shx=shx, dbf=dbf, shp=shp) as reader:
+ assert len(reader) == 1
+ assert reader.shape(0).shapeType == shapefile.NULL
+
+
+def test_write_context_path(tmpdir):
+ """
+ Assert that the Writer context manager
+ closes the shp, shx, and dbf files
+ on exit, if given paths.
+ """
+ with shapefile.Writer(tmpdir.join('test')) as sf:
+ sf.field('field1', 'C') # required to create a valid dbf file
+ sf.record('value')
+ sf.null()
+
+ assert sf.shp.closed is True
+ assert sf.dbf.closed is True
+ assert sf.shx.closed is True
+
+ # test that opens and reads correctly after
+ with shapefile.Reader(tmpdir.join('test')) as reader:
+ assert len(reader) == 1
+ assert reader.shape(0).shapeType == shapefile.NULL
+
+
+def test_write_context_filelike(tmpdir):
+ """
+ Assert that the Writer context manager
+ leaves the shp, shx, and dbf files open
+ on exit, if given filelike objects.
+ """
+ shp = open(tmpdir.join("test.shp").strpath, mode='wb+')
+ shx = open(tmpdir.join("test.shx").strpath, mode='wb+')
+ dbf = open(tmpdir.join("test.dbf").strpath, mode='wb+')
+ with shapefile.Writer(shx=shx, dbf=dbf, shp=shp) as sf:
+ sf.field('field1', 'C') # required to create a valid dbf file
+ sf.record('value')
+ sf.null()
+
+ assert sf.shp.closed is False
+ assert sf.dbf.closed is False
+ assert sf.shx.closed is False
+
+ # test that opens and reads correctly after
+ with shapefile.Reader(shx=shx, dbf=dbf, shp=shp) as reader:
+ assert len(reader) == 1
+ assert reader.shape(0).shapeType == shapefile.NULL
+
+
def test_write_shapefile_extension_ignored(tmpdir):
"""
Assert that the filename's extension is
@@ -1338,8 +1512,10 @@ def test_write_geojson(tmpdir):
assert json.dumps(r.shapeRecords().__geo_interface__)
assert json.dumps(r.__geo_interface__)
+
shape_types = [k for k in shapefile.SHAPETYPE_LOOKUP.keys() if k != 31] # exclude multipatch
+
@pytest.mark.parametrize("shape_type", shape_types)
def test_write_empty_shapefile(tmpdir, shape_type):
"""
View it on GitLab: https://salsa.debian.org/debian-gis-team/pyshp/-/commit/fb4a6705bcc47bb5cca1e3fa7242f00a92b961bc
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/pyshp/-/commit/fb4a6705bcc47bb5cca1e3fa7242f00a92b961bc
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20220728/f4f35484/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list