-
Notifications
You must be signed in to change notification settings - Fork 206
/
Copy pathdrvsupport.py
411 lines (361 loc) · 13.2 KB
/
drvsupport.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# -*- coding: utf-8 -*-
import os
from fiona.env import Env
from fiona._env import get_gdal_version_tuple
_GDAL_VERSION = get_gdal_version_tuple()
# Here is the list of available drivers as (name, modes) tuples. Currently,
# we only expose the defaults (excepting FileGDB). We also don't expose
# the CSV or GeoJSON drivers. Use Python's csv and json modules instead.
# Might still exclude a few more of these after making a pass through the
# entries for each at https://gdal.org/drivers/vector/index.html to screen
# out the multi-layer formats.
supported_drivers = dict([
# OGR Vector Formats
# Format Name Code Creation Georeferencing Compiled by default
# Aeronav FAA files AeronavFAA No Yes Yes
("AeronavFAA", "r"),
# ESRI ArcObjects ArcObjects No Yes No, needs ESRI ArcObjects
# Arc/Info Binary Coverage AVCBin No Yes Yes
# multi-layer
# ("AVCBin", "r"),
# Arc/Info .E00 (ASCII) Coverage AVCE00 No Yes Yes
# multi-layer
# ("AVCE00", "r"),
# Arc/Info Generate ARCGEN No No Yes
("ARCGEN", "r"),
# Atlas BNA BNA Yes No Yes
("BNA", "rw"),
# AutoCAD DWG DWG No No No
# AutoCAD DXF DXF Yes No Yes
("DXF", "rw"),
# Comma Separated Value (.csv) CSV Yes No Yes
("CSV", "raw"),
# CouchDB / GeoCouch CouchDB Yes Yes No, needs libcurl
# DODS/OPeNDAP DODS No Yes No, needs libdap
# EDIGEO EDIGEO No Yes Yes
# multi-layer? Hard to tell from the OGR docs
# ("EDIGEO", "r"),
# ElasticSearch ElasticSearch Yes (write-only) - No, needs libcurl
# ESRI FileGDB FileGDB Yes Yes No, needs FileGDB API library
# multi-layer
("FileGDB", "raw"),
("OpenFileGDB", "raw"),
# ESRI Personal GeoDatabase PGeo No Yes No, needs ODBC library
# ESRI ArcSDE SDE No Yes No, needs ESRI SDE
# ESRIJSON ESRIJSON No Yes Yes
("ESRIJSON", "r"),
# ESRI Shapefile ESRI Shapefile Yes Yes Yes
("ESRI Shapefile", "raw"),
# FMEObjects Gateway FMEObjects Gateway No Yes No, needs FME
("FlatGeobuf", "raw"),
# GeoJSON GeoJSON Yes Yes Yes
("GeoJSON", "raw"),
# GeoJSONSeq GeoJSON sequences Yes Yes Yes
("GeoJSONSeq", "raw"),
# Géoconcept Export Geoconcept Yes Yes Yes
# multi-layers
# ("Geoconcept", "raw"),
# Geomedia .mdb Geomedia No No No, needs ODBC library
# GeoPackage GPKG Yes Yes No, needs libsqlite3
("GPKG", "raw"),
# GeoRSS GeoRSS Yes Yes Yes (read support needs libexpat)
# Google Fusion Tables GFT Yes Yes No, needs libcurl
# GML GML Yes Yes Yes (read support needs Xerces or libexpat)
("GML", "rw"),
# GMT GMT Yes Yes Yes
("GMT", "rw"),
# GMT renamed to OGR_GMT for GDAL 2.x
("OGR_GMT", "rw"),
# GPSBabel GPSBabel Yes Yes Yes (needs GPSBabel and GPX driver)
# GPX GPX Yes Yes Yes (read support needs libexpat)
("GPX", "rw"),
# GRASS GRASS No Yes No, needs libgrass
# GPSTrackMaker (.gtm, .gtz) GPSTrackMaker Yes Yes Yes
# ("GPSTrackMaker", "rw"),
# Hydrographic Transfer Format HTF No Yes Yes
# TODO: Fiona is not ready for multi-layer formats: ("HTF", "r"),
# Idrisi Vector (.VCT) Idrisi No Yes Yes
("Idrisi", "r"),
# Informix DataBlade IDB Yes Yes No, needs Informix DataBlade
# INTERLIS "Interlis 1" and "Interlis 2" Yes Yes No, needs Xerces (INTERLIS model reading needs ili2c.jar)
# INGRES INGRES Yes No No, needs INGRESS
# KML KML Yes Yes Yes (read support needs libexpat)
# LIBKML LIBKML Yes Yes No, needs libkml
# Mapinfo File MapInfo File Yes Yes Yes
("MapInfo File", "raw"),
# Microstation DGN DGN Yes No Yes
("DGN", "raw"),
# Access MDB (PGeo and Geomedia capable) MDB No Yes No, needs JDK/JRE
# Memory Memory Yes Yes Yes
# MySQL MySQL No Yes No, needs MySQL library
# NAS - ALKIS NAS No Yes No, needs Xerces
# Oracle Spatial OCI Yes Yes No, needs OCI library
# ODBC ODBC No Yes No, needs ODBC library
# MS SQL Spatial MSSQLSpatial Yes Yes No, needs ODBC library
# Open Document Spreadsheet ODS Yes No No, needs libexpat
# OGDI Vectors (VPF, VMAP, DCW) OGDI No Yes No, needs OGDI library
# OpenAir OpenAir No Yes Yes
# multi-layer
# ("OpenAir", "r"),
# PCI Geomatics Database File PCIDSK No No Yes, using internal PCIDSK SDK (from GDAL 1.7.0)
("PCIDSK", "raw"),
# PDS PDS No Yes Yes
("PDS", "r"),
# PDS renamed to OGR_PDS for GDAL 2.x
("OGR_PDS", "r"),
# PGDump PostgreSQL SQL dump Yes Yes Yes
# PostgreSQL/PostGIS PostgreSQL/PostGIS Yes Yes No, needs PostgreSQL client library (libpq)
# EPIInfo .REC REC No No Yes
# S-57 (ENC) S57 No Yes Yes
# multi-layer
("S57", "r"),
# SDTS SDTS No Yes Yes
# multi-layer
# ("SDTS", "r"),
# SEG-P1 / UKOOA P1/90 SEGUKOOA No Yes Yes
# multi-layers
# ("SEGUKOOA", "r"),
# SEG-Y SEGY No No Yes
("SEGY", "r"),
# Norwegian SOSI Standard SOSI No Yes No, needs FYBA library
# SQLite/SpatiaLite SQLite Yes Yes No, needs libsqlite3 or libspatialite
("SQLite", "raw"),
# SUA SUA No Yes Yes
("SUA", "r"),
# SVG SVG No Yes No, needs libexpat
# TopoJSON TopoJSON No Yes Yes
("TopoJSON", "r"),
# UK .NTF UK. NTF No Yes Yes
# multi-layer
# ("UK. NTF", "r"),
# U.S. Census TIGER/Line TIGER No Yes Yes
# multi-layer
# ("TIGER", "r"),
# VFK data VFK No Yes Yes
# multi-layer
# ("VFK", "r"),
# VRT - Virtual Datasource VRT No Yes Yes
# multi-layer
# ("VRT", "r"),
# OGC WFS (Web Feature Service) WFS Yes Yes No, needs libcurl
# MS Excel format XLS No No No, needs libfreexl
# Office Open XML spreadsheet XLSX Yes No No, needs libexpat
# X-Plane/Flighgear aeronautical data XPLANE No Yes Yes
# multi-layer
# ("XPLANE", "r")
])
# Minimal gdal version for different modes
driver_mode_mingdal = {
'r': {'GPKG': (1, 11, 0),
'GeoJSONSeq': (2, 4, 0),
'FlatGeobuf': (3, 1, 0)},
'w': {'GPKG': (1, 11, 0),
'PCIDSK': (2, 0, 0),
'GeoJSONSeq': (2, 4, 0),
'FlatGeobuf': (3, 1, 3),
'OpenFileGDB': (3, 6, 0)},
'a': {'GPKG': (1, 11, 0),
'PCIDSK': (2, 0, 0),
'GeoJSON': (2, 1, 0),
'GeoJSONSeq': (3, 6, 0),
'MapInfo File': (2, 0, 0),
'FlatGeobuf': (3, 5, 1),
'OpenFileGDB': (3, 6, 0)}
}
def _driver_supports_mode(driver, mode):
""" Returns True if driver supports mode, False otherwise
Note: this function is not part of Fiona's public API.
"""
if driver not in supported_drivers:
return False
if mode not in supported_drivers[driver]:
return False
if driver in driver_mode_mingdal[mode]:
if _GDAL_VERSION < driver_mode_mingdal[mode][driver]:
return False
return True
# Removes drivers in the supported_drivers dictionary that the
# machine's installation of OGR due to how it is compiled.
# OGR may not have optional libraries compiled or installed.
def _filter_supported_drivers():
global supported_drivers
with Env() as gdalenv:
ogrdrv_names = gdalenv.drivers().keys()
supported_drivers_copy = supported_drivers.copy()
for drv in supported_drivers.keys():
if drv not in ogrdrv_names:
del supported_drivers_copy[drv]
supported_drivers = supported_drivers_copy
_filter_supported_drivers()
def vector_driver_extensions():
"""
Returns
-------
dict:
Map of extensions to the driver.
"""
from fiona.meta import extensions # prevent circular import
extension_to_driver = {}
for drv, modes in supported_drivers.items():
# update extensions based on driver suppport
for extension in extensions(drv) or ():
if "w" in modes:
extension_to_driver[extension] = extension_to_driver.get(extension, drv)
return extension_to_driver
def driver_from_extension(path):
"""
Attempt to auto-detect driver based on the extension.
Parameters
----------
path: str or pathlike object
The path to the dataset to write with.
Returns
-------
str:
The name of the driver for the extension.
"""
try:
# in case the path is a file handle
# or a partsed path
path = path.name
except AttributeError:
pass
driver_extensions = vector_driver_extensions()
try:
return driver_extensions[os.path.splitext(path)[-1].lstrip(".").lower()]
except KeyError:
raise ValueError("Unable to detect driver. Please specify driver.")
# driver_converts_to_str contains field type, driver combinations that are silently converted to string
# None: field type is always converted to str
# (2, 0, 0): starting from gdal 2.0 field type is not converted to string
_driver_converts_to_str = {
'time': {
'CSV': None,
'PCIDSK': None,
'GeoJSON': (2, 0, 0),
'GPKG': None,
'GMT': None,
'OGR_GMT': None
},
'datetime': {
'CSV': None,
'PCIDSK': None,
'GeoJSON': (2, 0, 0),
'GML': (3, 1, 0),
},
'date': {
'CSV': None,
'PCIDSK': None,
'GeoJSON': (2, 0, 0),
'GMT': None,
'OGR_GMT': None,
'GML': (3, 1, 0),
}
}
def _driver_converts_field_type_silently_to_str(driver, field_type):
""" Returns True if the driver converts the field_type silently to str, False otherwise
Note: this function is not part of Fiona's public API.
"""
if field_type in _driver_converts_to_str and driver in _driver_converts_to_str[field_type]:
if _driver_converts_to_str[field_type][driver] is None:
return True
elif _GDAL_VERSION < _driver_converts_to_str[field_type][driver]:
return True
return False
# None: field type is never supported, (2, 0, 0) field type is supported starting with gdal 2.0
_driver_field_type_unsupported = {
'time': {
'ESRI Shapefile': None,
'GPKG': (2, 0, 0),
'GPX': None,
'GPSTrackMaker': None,
'GML': (3, 1, 0),
'DGN': None,
'BNA': None,
'DXF': None,
'PCIDSK': (2, 1, 0),
'FileGDB': (3, 5, 0),
'FlatGeobuf': None,
'OpenFileGDB': None
},
'datetime': {
'ESRI Shapefile': None,
'GPKG': (2, 0, 0),
'DGN': None,
'BNA': None,
'DXF': None,
'PCIDSK': (2, 1, 0)
},
'date': {
'GPX': None,
'GPSTrackMaker': None,
'DGN': None,
'BNA': None,
'DXF': None,
'PCIDSK': (2, 1, 0),
'FileGDB': (3, 5, 0),
'FlatGeobuf': None,
'OpenFileGDB': None
}
}
def _driver_supports_field(driver, field_type):
""" Returns True if the driver supports the field_type, False otherwise
Note: this function is not part of Fiona's public API.
"""
if field_type in _driver_field_type_unsupported and driver in _driver_field_type_unsupported[field_type]:
if _driver_field_type_unsupported[field_type][driver] is None:
return False
elif _GDAL_VERSION < _driver_field_type_unsupported[field_type][driver]:
return False
return True
# None: field type never supports timezones, (2, 0, 0): field type supports timezones with GDAL 2.0.0
_drivers_not_supporting_timezones = {
'datetime': {
'MapInfo File': None,
'GPKG': (3, 1, 0),
'GPSTrackMaker': (3, 1, 1),
'FileGDB': None,
'SQLite': (2, 4, 0)
},
'time': {
'MapInfo File': None,
'GPKG': None,
'GPSTrackMaker': None,
'GeoJSON': None,
'GeoJSONSeq': None,
'GML': None,
'CSV': None,
'GMT': None,
'OGR_GMT': None,
'SQLite': None
}
}
def _driver_supports_timezones(driver, field_type):
""" Returns True if the driver supports timezones for field_type, False otherwise
Note: this function is not part of Fiona's public API.
"""
if field_type in _drivers_not_supporting_timezones and driver in _drivers_not_supporting_timezones[field_type]:
if _drivers_not_supporting_timezones[field_type][driver] is None:
return False
elif _GDAL_VERSION < _drivers_not_supporting_timezones[field_type][driver]:
return False
return True
# None: driver never supports timezones, (2, 0, 0): driver supports timezones with GDAL 2.0.0
_drivers_not_supporting_milliseconds = {
'GPSTrackMaker': None,
'FileGDB': None,
'OpenFileGDB': None
}
def _driver_supports_milliseconds(driver):
""" Returns True if the driver supports milliseconds, False otherwise
Note: this function is not part of Fiona's public API.
"""
# GDAL 2.0 introduced support for milliseconds
if _GDAL_VERSION.major < 2:
return False
if driver in _drivers_not_supporting_milliseconds:
if _drivers_not_supporting_milliseconds[driver] is None:
return False
elif _drivers_not_supporting_milliseconds[driver] < _GDAL_VERSION:
return False
return True