Skip to content

Commit 546489e

Browse files
authored
Merge pull request #310 from GeospatialPython/combine_iterRecords_range_into_iterRecords
Combine iter records range into iter records
2 parents 7fbbd8e + 763bd33 commit 546489e

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ part of your geospatial project.
9595

9696
# Version Changes
9797

98+
## 2.3.x
99+
100+
### New Features:
101+
- Reader.iterRecords now allows start and stop to be specified, to lookup smaller ranges of records.
102+
- Equality comparisons between Records now also require the fields to be the same (and in the same order).
103+
104+
### Development:
105+
- Code quality tools run on PyShp
106+
98107
## 2.3.1
99108

100109
### Bug fixes:
@@ -1467,6 +1476,7 @@ Karim Bahgat
14671476
karanrn
14681477
Kurt Schwehr
14691478
Kyle Kelley
1479+
Lionel Guez
14701480
Louis Tiao
14711481
Marcin Cuprjak
14721482
mcuprjak

shapefile.py

+29-4
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,12 @@ def __dir__(self):
854854
) # plus field names (random order if Python version < 3.6)
855855
return default + fnames
856856

857+
def __eq__(self, other):
858+
if isinstance(other, self.__class__):
859+
if self.__field_positions != other.__field_positions:
860+
return False
861+
return list.__eq__(self, other)
862+
857863

858864
class ShapeRecord(object):
859865
"""A ShapeRecord object containing a shape along with its attributes.
@@ -1325,7 +1331,9 @@ def __restrictIndex(self, i):
13251331
if self.numRecords:
13261332
rmax = self.numRecords - 1
13271333
if abs(i) > rmax:
1328-
raise IndexError("Shape or Record index out of range.")
1334+
raise IndexError(
1335+
"Shape or Record index: %s out of range. Max index: %s" % (i, rmax)
1336+
)
13291337
if i < 0:
13301338
i = range(self.numRecords)[i]
13311339
return i
@@ -1809,18 +1817,35 @@ def records(self, fields=None):
18091817
records.append(r)
18101818
return records
18111819

1812-
def iterRecords(self, fields=None):
1820+
def iterRecords(self, fields=None, start=0, stop=None):
18131821
"""Returns a generator of records in a dbf file.
18141822
Useful for large shapefiles or dbf files.
18151823
To only read some of the fields, specify the 'fields' arg as a
18161824
list of one or more fieldnames.
1825+
By default yields all records. Otherwise, specify start
1826+
(default: 0) or stop (default: number_of_records)
1827+
to only yield record numbers i, where
1828+
start <= i < stop, (or
1829+
start <= i < number_of_records + stop
1830+
if stop < 0).
18171831
"""
18181832
if self.numRecords is None:
18191833
self.__dbfHeader()
18201834
f = self.__getFileObj(self.dbf)
1821-
f.seek(self.__dbfHdrLength)
1835+
start = self.__restrictIndex(start)
1836+
if stop is None:
1837+
stop = self.numRecords
1838+
elif abs(stop) > self.numRecords:
1839+
raise IndexError(
1840+
"abs(stop): %s exceeds number of records: %s."
1841+
% (abs(stop), self.numRecords)
1842+
)
1843+
elif stop < 0:
1844+
stop = range(self.numRecords)[stop]
1845+
recSize = self.__recordLength
1846+
f.seek(self.__dbfHdrLength + (start * recSize))
18221847
fieldTuples, recLookup, recStruct = self.__recordFields(fields)
1823-
for i in xrange(self.numRecords):
1848+
for i in xrange(start, stop):
18241849
r = self.__record(
18251850
oid=i, fieldTuples=fieldTuples, recLookup=recLookup, recStruct=recStruct
18261851
)

test_shapefile.py

+45
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,51 @@ def test_record_oid():
972972
assert shaperec.record.oid == i
973973

974974

975+
def test_iterRecords_start_stop():
976+
"""
977+
Assert that Reader.iterRecords(start, stop)
978+
returns the correct records, as if searched for
979+
by index with Reader.record
980+
"""
981+
982+
with shapefile.Reader("shapefiles/blockgroups") as sf:
983+
N = len(sf)
984+
985+
# Arbitrary selection of record indices
986+
# (there are 663 records in blockgroups.dbf).
987+
for i in [
988+
0,
989+
1,
990+
2,
991+
3,
992+
5,
993+
11,
994+
17,
995+
33,
996+
51,
997+
103,
998+
170,
999+
234,
1000+
435,
1001+
543,
1002+
N - 3,
1003+
N - 2,
1004+
N - 1,
1005+
]:
1006+
for record in sf.iterRecords(start=i):
1007+
assert record == sf.record(record.oid)
1008+
1009+
for record in sf.iterRecords(stop=i):
1010+
assert record == sf.record(record.oid)
1011+
1012+
for stop in range(i, len(sf)):
1013+
# test negative indexing from end, as well as
1014+
# positive values of stop, and its default
1015+
for stop_arg in (stop, stop - len(sf)):
1016+
for record in sf.iterRecords(start=i, stop=stop_arg):
1017+
assert record == sf.record(record.oid)
1018+
1019+
9751020
def test_shape_oid():
9761021
"""
9771022
Assert that the shape's oid attribute returns

0 commit comments

Comments
 (0)