Skip to content

Commit 7f2c895

Browse files
authored
Merge branch 'master' into pyshp-3.0.0-mypy-strict
2 parents 2b029c8 + df3ac3d commit 7f2c895

File tree

5 files changed

+50
-50
lines changed

5 files changed

+50
-50
lines changed

.gitignore

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
shapefile_[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9].dbf
22
shapefile_[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9].shp
33
shapefile_[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9].shx
4-
shapefiles/test/copy.dbf
5-
shapefiles/test/copy.shp
6-
shapefiles/test/copy.shx
7-
shapefiles/test/geojson.dbf
8-
shapefiles/test/geojson.shp
9-
shapefiles/test/geojson.shx
10-
shapefiles/test/latin_as_utf8.dbf
11-
shapefiles/test/latin_as_utf8.shp
12-
shapefiles/test/latin_as_utf8.shx
13-
shapefiles/test/null.dbf
14-
shapefiles/test/null.shp
15-
shapefiles/test/null.shx
4+
shapefiles/test/testfile.*
5+
shapefiles/test/onlydbf.*
6+
shapefiles/test/contextwriter.*
7+
shapefiles/test/shapetype.*
8+
shapefiles/test/dtype.*
9+
shapefiles/test/null.*
10+
shapefiles/test/point.*
11+
shapefiles/test/line.*
12+
shapefiles/test/linem
13+
shapefiles/test/linez.*.*
14+
shapefiles/test/multipoint.*
15+
shapefiles/test/polygon.*
16+
shapefiles/test/multipatch.*
17+
shapefiles/test/copy.*
18+
shapefiles/test/balancing.*
19+
shapefiles/test/latin_as_utf8.*
20+
shapefiles/test/corrupt_too_long.*
21+
shapefiles/test/MyPolyZ.*
22+
shapefiles/test/NullTest.*
23+
shapefiles/test/geojson.*
1624
__pycache__/
1725
__cache__/
1826
build/

LICENSE.TXT

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
The MIT License (MIT)
22

3-
Copyright 2013 Joel Lawhead
3+
Copyright © 2013 Joel Lawhead
44

5-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
66

77
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
88

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The Python Shapefile Library (PyShp) reads and writes ESRI Shapefiles in pure Py
88

99
- **Author**: [Joel Lawhead](https://github.com/GeospatialPython)
1010
- **Maintainers**: [Karim Bahgat](https://github.com/karimbahgat)
11-
- **Version**: 3.0.0-alpha
11+
- **Version**: 3.0.0
1212
- **Date**: 3rd August, 2025
1313
- **License**: [MIT](https://github.com/GeospatialPython/pyshp/blob/master/LICENSE.TXT)
1414

@@ -93,7 +93,7 @@ part of your geospatial project.
9393

9494
# Version Changes
9595

96-
## 3.0.0-alpha
96+
## 3.0.0
9797

9898
### Breaking Changes:
9999
- Python 2 and Python 3.8 support dropped.

changelog.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
VERSION Next
12
Improvements:
23
* LICENSE.TXT re-encoded in UTF-8 (@musicinmybrain)
34

4-
VERSION 3.0.0-alpha
5+
VERSION 3.0.0
56

67
2025-08-03
78
Breaking Changes:

src/shapefile.py

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from __future__ import annotations
1010

11-
__version__ = "3.0.0-alpha"
11+
__version__ = "3.0.0"
1212

1313
import array
1414
import doctest
@@ -325,7 +325,10 @@ class GeoJSONFeatureCollection(TypedDict):
325325

326326

327327
class GeoJSONFeatureCollectionWithBBox(GeoJSONFeatureCollection):
328-
# bbox is technically optional under the spec
328+
# bbox is technically optional under the spec but this seems
329+
# a very minor improvement that would require NotRequired
330+
# from the typing-extensions backport for Python 3.9
331+
# (PyShp's resisted having any other dependencies so far!)
329332
bbox: list[float]
330333

331334

@@ -726,6 +729,11 @@ def __init__(
726729
are designated by their starting index in geometry record's
727730
list of shapes. For MultiPatch geometry, partTypes designates
728731
the patch type of each of the parts.
732+
Lines allows the points-lists and parts to be denoted together
733+
in one argument. It is intended for multiple point shapes
734+
(polylines, polygons and multipatches) but if used as a length-1
735+
nested list for a multipoint (instead of points for some reason)
736+
PyShp will not complain, as multipoints only have 1 part internally.
729737
"""
730738

731739
# Preserve previous behaviour for anyone who set self.shapeType = None
@@ -741,7 +749,6 @@ def __init__(
741749
default_points: PointsT = []
742750
default_parts: list[int] = []
743751

744-
# Make sure polygon rings (parts) are closed
745752
if lines is not None:
746753
if self.shapeType in Polygon_shapeTypes:
747754
lines = list(lines)
@@ -1072,7 +1079,7 @@ def __repr__(self) -> str:
10721079
class NullShape(Shape):
10731080
# Shape.shapeType = NULL already,
10741081
# to preserve handling of default args in Shape.__init__
1075-
# Repeated for clarity.
1082+
# Repeated for the avoidance of doubt.
10761083
def __init__(
10771084
self,
10781085
oid: Optional[int] = None,
@@ -1117,8 +1124,8 @@ def write_to_byte_stream(
11171124

11181125
class _CanHaveBBox(Shape):
11191126
"""As well as setting bounding boxes, we also utilize the
1120-
fact that this mixin applies to all the shapes that are
1121-
not a single point.
1127+
fact that this mixin only applies to all the shapes that are
1128+
not a single point (polylines, polygons, multipatches and multipoints).
11221129
"""
11231130

11241131
@staticmethod
@@ -1203,10 +1210,6 @@ def from_byte_stream(
12031210
b_io, nParts
12041211
)
12051212

1206-
# else:
1207-
# parts = None
1208-
# partTypes = None
1209-
12101213
if nPoints:
12111214
kwargs["points"] = cast(
12121215
PointsT, cls._read_points_from_byte_stream(b_io, nPoints)
@@ -1222,25 +1225,7 @@ def from_byte_stream(
12221225
b_io, nPoints, next_shape
12231226
)
12241227

1225-
# else:
1226-
# points = None
1227-
# zbox, zs = None, None
1228-
# mbox, ms = None, None
1229-
12301228
return ShapeClass(**kwargs)
1231-
# return ShapeClass(
1232-
# shapeType=shapeType,
1233-
# # Mypy 1.17.1 doesn't figure out that an Optional[list[Point2D]] is an Optional[list[PointT]]
1234-
# points=cast(Optional[PointsT], points),
1235-
# parts=parts,
1236-
# partTypes=partTypes,
1237-
# oid=oid,
1238-
# m=ms,
1239-
# z=zs,
1240-
# bbox=shape_bbox,
1241-
# mbox=mbox,
1242-
# zbox=zbox,
1243-
# )
12441229

12451230
@staticmethod
12461231
def write_to_byte_stream(
@@ -1249,7 +1234,7 @@ def write_to_byte_stream(
12491234
i: int,
12501235
) -> int:
12511236
# We use static methods here and below,
1252-
# to support s only being an instance of a the
1237+
# to support s only being an instance of the
12531238
# Shape base class (with shapeType set)
12541239
# i.e. not necessarily one of our newer shape specific
12551240
# sub classes.
@@ -2368,6 +2353,10 @@ def __init__(
23682353
# Close and delete the temporary zipfile
23692354
try:
23702355
zipfileobj.close()
2356+
# TODO Does catching all possible exceptions really increase
2357+
# the chances of closing the zipfile successully, or does it
2358+
# just mean .close() failures will still fail, but fail
2359+
# silently?
23712360
except: # noqa: E722
23722361
pass
23732362
# Try to load shapefile
@@ -3610,15 +3599,16 @@ def shape(
36103599
# Check is shape or import from geojson
36113600
if not isinstance(s, Shape):
36123601
if hasattr(s, "__geo_interface__"):
3613-
s = s.__geo_interface__ # type: ignore [assignment]
3602+
shape_dict = cast(dict, s.__geo_interface__)
36143603
if isinstance(s, dict):
3615-
s = Shape._from_geojson(cast(GeoJSONHomogeneousGeometryObject, s))
3604+
shape_dict = Shape._from_geojson(cast(GeoJSONHomogeneousGeometryObject, s))
36163605
else:
36173606
raise TypeError(
36183607
"Can only write Shape objects, GeoJSON dictionaries, "
36193608
"or objects with the __geo_interface__, "
36203609
f"not: {s}"
36213610
)
3611+
s = Shape._from_geojson(shape_dict)
36223612
# Write to file
36233613
offset, length = self.__shpRecord(s)
36243614
if self.shx:
@@ -3660,7 +3650,8 @@ def __shpRecord(self, s: Shape) -> tuple[int, int]:
36603650
# Record number, Content length place holder
36613651
b_io.write(pack(">2i", self.shpNum, -1))
36623652

3663-
# Track number of content bytes written. Excluding self.shpNum and length t.b.c.
3653+
# Track number of content bytes written, excluding
3654+
# self.shpNum and length (t.b.c.)
36643655
n = 0
36653656

36663657
n += b_io.write(pack("<i", s.shapeType))
@@ -4022,7 +4013,7 @@ def _filter_network_doctests(
40224013

40234014
def _replace_remote_url(
40244015
old_url: str,
4025-
# Default port of Python http.server and Python 2's SimpleHttpServer
4016+
# Default port of Python http.server
40264017
port: int = 8000,
40274018
scheme: str = "http",
40284019
netloc: str = "localhost",

0 commit comments

Comments
 (0)