|
3 | 3 | Provides read and write support for ESRI Shapefiles. |
4 | 4 | authors: jlawhead<at>geospatialpython.com |
5 | 5 | maintainer: karim.bahgat.norway<at>gmail.com |
6 | | -Compatible with Python versions 2.7-3.x |
| 6 | +Compatible with Python versions >= 3.8 |
7 | 7 | """ |
8 | 8 |
|
9 | 9 | __version__ = "2.3.1" |
10 | 10 |
|
11 | | -from struct import pack, unpack, calcsize, error, Struct |
| 11 | +import array |
| 12 | +from datetime import date |
| 13 | +import io |
| 14 | +import logging |
12 | 15 | import os |
| 16 | +from struct import pack, unpack, calcsize, error, Struct |
13 | 17 | import sys |
14 | | -import time |
15 | | -import array |
16 | 18 | import tempfile |
17 | | -import logging |
18 | | -import io |
19 | | -from datetime import date |
| 19 | +import time |
20 | 20 | import zipfile |
21 | 21 |
|
| 22 | +from urllib.error import HTTPError |
| 23 | +from urllib.parse import urlparse, urlunparse |
| 24 | +from urllib.request import urlopen, Request |
| 25 | + |
22 | 26 | # Create named logger |
23 | 27 | logger = logging.getLogger(__name__) |
24 | 28 |
|
|
74 | 78 | 5: 'RING'} |
75 | 79 |
|
76 | 80 |
|
77 | | -# Python 2-3 handling |
78 | | - |
79 | | -PYTHON3 = sys.version_info[0] == 3 |
80 | | - |
81 | | -if PYTHON3: |
82 | | - xrange = range |
83 | | - izip = zip |
84 | | - |
85 | | - from urllib.parse import urlparse, urlunparse |
86 | | - from urllib.error import HTTPError |
87 | | - from urllib.request import urlopen, Request |
88 | | - |
89 | | -else: |
90 | | - from itertools import izip |
91 | | - |
92 | | - from urlparse import urlparse, urlunparse |
93 | | - from urllib2 import HTTPError |
94 | | - from urllib2 import urlopen, Request |
95 | | - |
96 | | - |
| 81 | +xrange = range |
| 82 | +izip = zip |
| 83 | + |
97 | 84 | # Helpers |
98 | 85 |
|
99 | 86 | MISSING = [None,''] |
100 | 87 | NODATA = -10e38 # as per the ESRI shapefile spec, only used for m-values. |
101 | 88 |
|
102 | | -if PYTHON3: |
103 | | - def b(v, encoding='utf-8', encodingErrors='strict'): |
104 | | - if isinstance(v, str): |
105 | | - # For python 3 encode str to bytes. |
106 | | - return v.encode(encoding, encodingErrors) |
107 | | - elif isinstance(v, bytes): |
108 | | - # Already bytes. |
109 | | - return v |
110 | | - elif v is None: |
111 | | - # Since we're dealing with text, interpret None as "" |
112 | | - return b"" |
113 | | - else: |
114 | | - # Force string representation. |
115 | | - return str(v).encode(encoding, encodingErrors) |
116 | | - |
117 | | - def u(v, encoding='utf-8', encodingErrors='strict'): |
118 | | - if isinstance(v, bytes): |
119 | | - # For python 3 decode bytes to str. |
120 | | - return v.decode(encoding, encodingErrors) |
121 | | - elif isinstance(v, str): |
122 | | - # Already str. |
123 | | - return v |
124 | | - elif v is None: |
125 | | - # Since we're dealing with text, interpret None as "" |
126 | | - return "" |
127 | | - else: |
128 | | - # Force string representation. |
129 | | - return bytes(v).decode(encoding, encodingErrors) |
130 | | - |
131 | | - def is_string(v): |
132 | | - return isinstance(v, str) |
133 | | - |
134 | | -else: |
135 | | - def b(v, encoding='utf-8', encodingErrors='strict'): |
136 | | - if isinstance(v, unicode): |
137 | | - # For python 2 encode unicode to bytes. |
138 | | - return v.encode(encoding, encodingErrors) |
139 | | - elif isinstance(v, bytes): |
140 | | - # Already bytes. |
141 | | - return v |
142 | | - elif v is None: |
143 | | - # Since we're dealing with text, interpret None as "" |
144 | | - return "" |
145 | | - else: |
146 | | - # Force string representation. |
147 | | - return unicode(v).encode(encoding, encodingErrors) |
148 | | - |
149 | | - def u(v, encoding='utf-8', encodingErrors='strict'): |
150 | | - if isinstance(v, bytes): |
151 | | - # For python 2 decode bytes to unicode. |
152 | | - return v.decode(encoding, encodingErrors) |
153 | | - elif isinstance(v, unicode): |
154 | | - # Already unicode. |
155 | | - return v |
156 | | - elif v is None: |
157 | | - # Since we're dealing with text, interpret None as "" |
158 | | - return u"" |
159 | | - else: |
160 | | - # Force string representation. |
161 | | - return bytes(v).decode(encoding, encodingErrors) |
| 89 | +def b(v, encoding='utf-8', encodingErrors='strict'): |
| 90 | + if isinstance(v, str): |
| 91 | + # For python 3 encode str to bytes. |
| 92 | + return v.encode(encoding, encodingErrors) |
| 93 | + elif isinstance(v, bytes): |
| 94 | + # Already bytes. |
| 95 | + return v |
| 96 | + elif v is None: |
| 97 | + # Since we're dealing with text, interpret None as "" |
| 98 | + return b"" |
| 99 | + else: |
| 100 | + # Force string representation. |
| 101 | + return str(v).encode(encoding, encodingErrors) |
| 102 | + |
| 103 | +def u(v, encoding='utf-8', encodingErrors='strict'): |
| 104 | + if isinstance(v, bytes): |
| 105 | + # For python 3 decode bytes to str. |
| 106 | + return v.decode(encoding, encodingErrors) |
| 107 | + elif isinstance(v, str): |
| 108 | + # Already str. |
| 109 | + return v |
| 110 | + elif v is None: |
| 111 | + # Since we're dealing with text, interpret None as "" |
| 112 | + return "" |
| 113 | + else: |
| 114 | + # Force string representation. |
| 115 | + return bytes(v).decode(encoding, encodingErrors) |
162 | 116 |
|
163 | | - def is_string(v): |
164 | | - return isinstance(v, basestring) |
| 117 | +def is_string(v): |
| 118 | + return isinstance(v, str) |
165 | 119 |
|
166 | | -if sys.version_info[0:2] >= (3, 6): |
167 | | - def pathlike_obj(path): |
168 | | - if isinstance(path, os.PathLike): |
169 | | - return os.fsdecode(path) |
170 | | - else: |
171 | | - return path |
172 | | -else: |
173 | | - def pathlike_obj(path): |
174 | | - if is_string(path): |
175 | | - return path |
176 | | - elif hasattr(path, "__fspath__"): |
177 | | - return path.__fspath__() |
178 | | - else: |
179 | | - try: |
180 | | - return str(path) |
181 | | - except: |
182 | | - return path |
| 120 | + |
| 121 | +def pathlike_obj(path): |
| 122 | + if isinstance(path, os.PathLike): |
| 123 | + return os.fsdecode(path) |
| 124 | + else: |
| 125 | + return path |
183 | 126 |
|
184 | 127 |
|
185 | 128 | # Begin |
@@ -452,7 +395,7 @@ def organize_polygon_rings(rings, return_errors=None): |
452 | 395 | polys = [[ext] for ext in exteriors] |
453 | 396 | return polys |
454 | 397 |
|
455 | | -class Shape(object): |
| 398 | +class Shape: |
456 | 399 | def __init__(self, shapeType=NULL, points=None, parts=None, partTypes=None, oid=None): |
457 | 400 | """Stores the geometry of the different shape types |
458 | 401 | specified in the Shapefile spec. Shape types are |
@@ -823,9 +766,9 @@ def __dir__(self): |
823 | 766 | """ |
824 | 767 | default = list(dir(type(self))) # default list methods and attributes of this class |
825 | 768 | fnames = list(self.__field_positions.keys()) # plus field names (random order if Python version < 3.6) |
826 | | - return default + fnames |
827 | | - |
828 | | -class ShapeRecord(object): |
| 769 | + return default + fnames |
| 770 | + |
| 771 | +class ShapeRecord: |
829 | 772 | """A ShapeRecord object containing a shape along with its attributes. |
830 | 773 | Provides the GeoJSON __geo_interface__ to return a Feature dictionary.""" |
831 | 774 | def __init__(self, shape=None, record=None): |
@@ -874,7 +817,7 @@ class ShapefileException(Exception): |
874 | 817 | """An exception to handle shapefile specific problems.""" |
875 | 818 | pass |
876 | 819 |
|
877 | | -class Reader(object): |
| 820 | +class Reader: |
878 | 821 | """Reads the three files of a shapefile as a unit or |
879 | 822 | separately. If one of the three files (.shp, .shx, |
880 | 823 | .dbf) is missing no exception is thrown until you try |
@@ -1756,7 +1699,7 @@ def iterShapeRecords(self, fields=None, bbox=None): |
1756 | 1699 | yield ShapeRecord(shape=shape, record=record) |
1757 | 1700 |
|
1758 | 1701 |
|
1759 | | -class Writer(object): |
| 1702 | +class Writer: |
1760 | 1703 | """Provides write support for ESRI Shapefiles.""" |
1761 | 1704 | def __init__(self, target=None, shapeType=None, autoBalance=False, **kwargs): |
1762 | 1705 | self.target = target |
|
0 commit comments