django-gisserver 2.0__py3-none-any.whl → 2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {django_gisserver-2.0.dist-info → django_gisserver-2.1.dist-info}/METADATA +26 -10
  2. django_gisserver-2.1.dist-info/RECORD +68 -0
  3. {django_gisserver-2.0.dist-info → django_gisserver-2.1.dist-info}/WHEEL +1 -1
  4. gisserver/__init__.py +1 -1
  5. gisserver/crs.py +401 -0
  6. gisserver/db.py +71 -5
  7. gisserver/exceptions.py +106 -2
  8. gisserver/extensions/functions.py +122 -28
  9. gisserver/extensions/queries.py +15 -10
  10. gisserver/features.py +44 -36
  11. gisserver/geometries.py +64 -306
  12. gisserver/management/commands/loadgeojson.py +41 -21
  13. gisserver/operations/base.py +11 -7
  14. gisserver/operations/wfs20.py +31 -93
  15. gisserver/output/__init__.py +6 -2
  16. gisserver/output/base.py +28 -13
  17. gisserver/output/csv.py +18 -6
  18. gisserver/output/geojson.py +7 -6
  19. gisserver/output/gml32.py +43 -23
  20. gisserver/output/results.py +25 -39
  21. gisserver/output/utils.py +9 -2
  22. gisserver/parsers/ast.py +171 -65
  23. gisserver/parsers/fes20/__init__.py +76 -4
  24. gisserver/parsers/fes20/expressions.py +97 -27
  25. gisserver/parsers/fes20/filters.py +9 -6
  26. gisserver/parsers/fes20/identifiers.py +27 -7
  27. gisserver/parsers/fes20/lookups.py +8 -6
  28. gisserver/parsers/fes20/operators.py +101 -49
  29. gisserver/parsers/fes20/sorting.py +14 -6
  30. gisserver/parsers/gml/__init__.py +10 -19
  31. gisserver/parsers/gml/base.py +32 -14
  32. gisserver/parsers/gml/geometries.py +48 -21
  33. gisserver/parsers/ows/kvp.py +10 -2
  34. gisserver/parsers/ows/requests.py +6 -4
  35. gisserver/parsers/query.py +6 -2
  36. gisserver/parsers/values.py +61 -4
  37. gisserver/parsers/wfs20/__init__.py +2 -0
  38. gisserver/parsers/wfs20/adhoc.py +25 -17
  39. gisserver/parsers/wfs20/base.py +12 -7
  40. gisserver/parsers/wfs20/projection.py +3 -3
  41. gisserver/parsers/wfs20/requests.py +1 -0
  42. gisserver/parsers/wfs20/stored.py +3 -2
  43. gisserver/parsers/xml.py +12 -0
  44. gisserver/projection.py +17 -7
  45. gisserver/static/gisserver/index.css +8 -3
  46. gisserver/templates/gisserver/base.html +12 -0
  47. gisserver/templates/gisserver/index.html +9 -15
  48. gisserver/templates/gisserver/service_description.html +12 -6
  49. gisserver/templates/gisserver/wfs/feature_field.html +1 -1
  50. gisserver/templates/gisserver/wfs/feature_type.html +35 -13
  51. gisserver/types.py +150 -81
  52. gisserver/views.py +47 -24
  53. django_gisserver-2.0.dist-info/RECORD +0 -66
  54. {django_gisserver-2.0.dist-info → django_gisserver-2.1.dist-info/licenses}/LICENSE +0 -0
  55. {django_gisserver-2.0.dist-info → django_gisserver-2.1.dist-info}/top_level.txt +0 -0
gisserver/views.py CHANGED
@@ -21,6 +21,7 @@ from gisserver.exceptions import (
21
21
  OperationProcessingFailed,
22
22
  OWSException,
23
23
  PermissionDenied,
24
+ XmlElementNotSupported,
24
25
  )
25
26
  from gisserver.features import FeatureType, ServiceDescription
26
27
  from gisserver.operations import base, wfs20
@@ -46,7 +47,7 @@ class OWSView(View):
46
47
  #: Define the namespace to use in the XML
47
48
  xml_namespace = "http://example.org/gisserver"
48
49
 
49
- #: Define namespace aliases to use, default is {"app": self.xml_namespace}
50
+ #: Define namespace aliases to use, default is ``{"app": self.xml_namespace}``.
50
51
  xml_namespace_aliases = None
51
52
 
52
53
  #: Default version to use
@@ -102,6 +103,7 @@ class OWSView(View):
102
103
  def get_xml_namespace_aliases(cls) -> dict[str, str]:
103
104
  """Provide all namespaces aliases with a namespace.
104
105
  This is most useful for parsing input.
106
+ The default is: ``{"app": cls.xml_namespace}``.
105
107
  """
106
108
  return cls.xml_namespace_aliases or {"app": cls.xml_namespace}
107
109
 
@@ -109,6 +111,7 @@ class OWSView(View):
109
111
  def get_xml_namespaces_to_prefixes(cls) -> dict[str, str]:
110
112
  """Provide a mapping from namespace to prefix.
111
113
  This is most useful for rendering output.
114
+ The default is: ``{cls.xml_namespace: "app"}``.
112
115
  """
113
116
  return {
114
117
  xml_namespace: prefix
@@ -119,7 +122,7 @@ class OWSView(View):
119
122
  """Entry point to handle HTTP GET requests.
120
123
 
121
124
  This parses the 'SERVICE' and 'REQUEST' parameters,
122
- to call the proper operation.
125
+ to call the proper :class:`~gisserver.operations.base.WFSOperation`.
123
126
 
124
127
  All query parameters are handled as case-insensitive.
125
128
  """
@@ -127,7 +130,9 @@ class OWSView(View):
127
130
  if logger.isEnabledFor(logging.DEBUG):
128
131
  logger.debug(
129
132
  "Parsing GET parameters:\n%s",
130
- unquote_plus(request.META["QUERY_STRING"].replace("&", "\n")),
133
+ unquote_plus(
134
+ request.META["QUERY_STRING"].replace("\n&", "\n").replace("&", "\n")
135
+ ).rstrip(),
131
136
  )
132
137
  self.kvp = kvp = KVPRequest(request.GET, ns_aliases=self.get_xml_namespace_aliases())
133
138
 
@@ -159,7 +164,7 @@ class OWSView(View):
159
164
  """Entry point to handle HTTP POST requests.
160
165
 
161
166
  This parses the XML to get the correct service and operation,
162
- to call the proper WFSMethod.
167
+ to call the proper :class:`~gisserver.operations.base.WFSOperation`.
163
168
  """
164
169
  # Parse the XML body
165
170
  if logger.isEnabledFor(logging.DEBUG):
@@ -177,17 +182,24 @@ class OWSView(View):
177
182
  if self.default_service
178
183
  else root.get_str_attribute("service")
179
184
  )
180
- operation = split_ns(root.tag)[1]
185
+
186
+ # Perform early version check. version can be omitted for GetCapabilities
187
+ self.set_version(service, root.attrib.get("version"))
188
+
189
+ # Find the registered operation that handles the request
190
+ namespace, operation = split_ns(root.tag)
181
191
  wfs_operation_cls = self.get_operation_class(service, operation)
182
192
 
183
- # Parse the request syntax
184
- request_cls = wfs_operation_cls.parser_class or resolve_xml_parser_class(root)
185
193
  try:
194
+ # Parse the request syntax
195
+ request_cls = wfs_operation_cls.parser_class or resolve_xml_parser_class(root)
186
196
  self.ows_request = request_cls.from_xml(root)
187
- self.set_version(service, self.ows_request.version)
188
197
 
189
198
  # Process the request!
190
199
  return self.call_operation(wfs_operation_cls)
200
+ except XmlElementNotSupported as e:
201
+ # Unknown XML element, e.g. wrong namespace.
202
+ raise OperationNotSupported(str(e), locator=root.attrib.get("handle")) from e
191
203
  except (OperationParsingFailed, OperationProcessingFailed) as e:
192
204
  # The WFS spec dictates that these exceptions
193
205
  # (and ResponseCacheExpired, CannotLockAllFeatures, FeaturesNotLocked which we don't raise)
@@ -275,7 +287,7 @@ class OWSView(View):
275
287
  except KeyError:
276
288
  allowed = ", ".join(sorted(self.accept_operations.keys()))
277
289
  raise InvalidParameterValue(
278
- f"'{service}' is an invalid service, supported are: {allowed}.",
290
+ f"'{service}' is not supported, available are: {allowed}.",
279
291
  locator="service",
280
292
  ) from None
281
293
 
@@ -305,6 +317,13 @@ class OWSView(View):
305
317
 
306
318
  def set_version(self, service: str, version: str | None):
307
319
  """Enforce a particular version based on the request."""
320
+ if service.upper() not in self.accept_operations:
321
+ allowed = ", ".join(sorted(self.accept_operations.keys()))
322
+ raise InvalidParameterValue(
323
+ f"'{service}' is not supported, available are: {allowed}.",
324
+ locator="service",
325
+ ) from None
326
+
308
327
  if not version:
309
328
  return
310
329
 
@@ -314,7 +333,7 @@ class OWSView(View):
314
333
 
315
334
  if version not in self.accept_versions:
316
335
  raise InvalidParameterValue(
317
- f"{service} Server does not support VERSION {version}.", locator="version"
336
+ f"This server does not support {service} version {version}.", locator="version"
318
337
  )
319
338
 
320
339
  # Enforce the requested version
@@ -417,30 +436,34 @@ class WFSView(OWSView):
417
436
  feature_type.bind_namespace(default_xml_namespace=self.xml_namespace)
418
437
  return feature_types
419
438
 
420
- def get_index_context_data(self, **kwargs):
421
- """Add WFS specific metadata"""
422
- get_feature_operation = self.accept_operations["WFS"]["GetFeature"]
423
- operation = get_feature_operation(self, ows_request=None)
424
-
425
- # Remove aliases
426
- wfs_output_formats = []
427
- seen = set()
428
- for output_format in operation.get_output_formats():
429
- if output_format.identifier not in seen:
430
- wfs_output_formats.append(output_format)
431
- seen.add(output_format.identifier)
432
-
439
+ def get_index_context_data(self, **kwargs) -> dict:
440
+ """Get the context data for the index template"""
433
441
  context = super().get_index_context_data(**kwargs)
434
442
  context.update(
435
443
  {
444
+ "GISSERVER_SUPPORTED_CRS_ONLY": conf.GISSERVER_SUPPORTED_CRS_ONLY,
436
445
  "wfs_features": self.get_bound_feature_types(),
437
- "wfs_output_formats": wfs_output_formats,
446
+ "wfs_output_formats": self._get_wfs_output_formats(),
438
447
  "wfs_filter_capabilities": self.wfs_filter_capabilities,
439
448
  "wfs_service_constraints": self.wfs_service_constraints,
440
449
  }
441
450
  )
442
451
  return context
443
452
 
453
+ def _get_wfs_output_formats(self) -> list[base.OutputFormat]:
454
+ """Find the output formats of the ``GetFeature`` operation for the HTML index."""
455
+ get_feature_operation = self.accept_operations["WFS"]["GetFeature"]
456
+ operation = get_feature_operation(self, ows_request=None)
457
+
458
+ # Get output formats, remove duplicates (e.g. GeoJSON/geojson alias)
459
+ wfs_output_formats = []
460
+ seen = set()
461
+ for output_format in operation.get_output_formats():
462
+ if output_format.identifier not in seen:
463
+ wfs_output_formats.append(output_format)
464
+ seen.add(output_format.identifier)
465
+ return wfs_output_formats
466
+
444
467
  def get_xml_schema_url(self, feature_types: list[FeatureType]) -> str:
445
468
  """Return the XML schema URL for the given feature types.
446
469
  This is used in the GML output rendering.
@@ -1,66 +0,0 @@
1
- gisserver/__init__.py,sha256=e6waXF42UPN4o15WEYAQ7DskYjyZB_gs3IANkuyGZUk,38
2
- gisserver/compat.py,sha256=qmLeT7wGRIyA2ujUtVEuUX7qgr98snak9b5OTvnkhas,451
3
- gisserver/conf.py,sha256=ppoyVS95mMoQXVbPxPar-tkq1t7fE0J3F6IyKitMWuA,2563
4
- gisserver/db.py,sha256=G4xF3xd8BQjGbKdf6QpOwzUfnm-phTarS71IRCV0Rys,5385
5
- gisserver/exceptions.py,sha256=q0EZJrlZ7JPf8tWB9de6fPWX74JBrlsoHYN4pBdCGck,6132
6
- gisserver/features.py,sha256=b7XrDC8XMn6SK3YdOuC5DvXlral5losrFrCeweecJUM,35744
7
- gisserver/geometries.py,sha256=Ok9e6fbAhW32iglg6gc955z0ZTN2p2lQd3WlN-FPJho,12338
8
- gisserver/projection.py,sha256=TStCF9xF4V_aozKqTD8uW9mPofZogobVDpdltXwsyZo,14859
9
- gisserver/types.py,sha256=5J18OUeL8o0VOdxlMGn7fPja7z4s-9Dgy6G-cjXReZM,41453
10
- gisserver/views.py,sha256=e7Bqr05FaflXOjOXMfQSix59bHqRmb_ASCRqqJlWqEY,18998
11
- gisserver/extensions/__init__.py,sha256=MsYUsNsoxxjeDHhx4DW9eGXvmOnI5PkoUXvKxRZaRRw,136
12
- gisserver/extensions/functions.py,sha256=Gv_IoWgJbCONbGg2P4GXdZDI18GvNtHDWLWQjOQMJLY,9085
13
- gisserver/extensions/queries.py,sha256=_UNWjHMgGgWtBzOl9Ez587e6WeE1_9uN8Qyjzfi4PMo,9435
14
- gisserver/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- gisserver/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- gisserver/management/commands/loadgeojson.py,sha256=bdCdt37cKPIYV9cQtLFJ0BzFcVgQQ9y59kTtPX7bYkA,11493
17
- gisserver/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- gisserver/operations/base.py,sha256=m56SRTnC6GVWfwugtXgdlIVNh6Vr1h8r_OdfBjWQQ5M,9839
19
- gisserver/operations/wfs20.py,sha256=WIvGXg1-M01s52VB8nSJGM0tKoviMhnNghQIrfqzudM,24226
20
- gisserver/output/__init__.py,sha256=5DTFnVEvs-lno_6lOOZheXhF4F96VkwAk71Q5juYe1M,977
21
- gisserver/output/base.py,sha256=EF3PFUrj2pGzbh2Yt4bpjlwkoGDoI63rHn6wkstXA3g,10303
22
- gisserver/output/csv.py,sha256=wKtcgwY37NjeLhBxAm2qgKk8UDX-4uUZEzK9LmmVKrQ,6624
23
- gisserver/output/geojson.py,sha256=fTEB-MRaYLYbJzQVvmZ8ev-Cwrl3lgsR8Jif2zWYSKg,11525
24
- gisserver/output/gml32.py,sha256=OtBXGup5m1GA9dM_p33E9IXtD-9KcZ58MgMyg-lkGd4,32567
25
- gisserver/output/iters.py,sha256=YbvtIIy977Snm5m7cYyQext0GCpo8S_u4azTCBNqqgw,8355
26
- gisserver/output/results.py,sha256=vvwJK1JEgRbs9S4sg5fmsd_avw5ztiC107OizygHk5M,15149
27
- gisserver/output/stored.py,sha256=m3JcR4MUilyuM_5J6XJDOIyzrhRJbcpg-6FMKy69csc,5763
28
- gisserver/output/utils.py,sha256=H4lD5Dn_xo8lAHcFv5LjKyj-SNMzzZsZrtDny9HISXk,2671
29
- gisserver/output/xmlschema.py,sha256=fHj8h9-vG508uRmM-kD5r2omde2wa_myJWWwcWe2lus,6445
30
- gisserver/parsers/__init__.py,sha256=eGORBeT0F8fR3AadV1uq8dbCeZtIeK0-__CcXwSvXgs,402
31
- gisserver/parsers/ast.py,sha256=DVUF3977RTjIpsu5yxbKS23Yxepn6JMj1NIUdRmQq2Q,11806
32
- gisserver/parsers/query.py,sha256=Ndipmq94reShe-DNKwJ96Ig0GdmshRhtVIF6OEGMGeg,6386
33
- gisserver/parsers/values.py,sha256=7AuOX8Zgb6Cnwb1FuY8Jl0r6TbLrGlNmhICw48sNiCE,2320
34
- gisserver/parsers/xml.py,sha256=jMsK1enKN0i_rdtjzGqcKdxnr9-n2-9jPY6hX56sU4g,9309
35
- gisserver/parsers/fes20/__init__.py,sha256=ji0bIRap4fvNW_WWhjnbkBm7ozuEblccIHNzL403Y3E,883
36
- gisserver/parsers/fes20/expressions.py,sha256=sjBO-S0aQDIorAPg6z7SSUwOreveJEA0w7qcj26UXoA,11275
37
- gisserver/parsers/fes20/filters.py,sha256=nMAQwgSXl2c7SvVZY_PJSO9XSf55ltvDPnCmIQ5SM9s,6518
38
- gisserver/parsers/fes20/identifiers.py,sha256=E-6ijz050fjoG-wyzzaIYwxVPplE9RVtoLN_iFNIYw8,3513
39
- gisserver/parsers/fes20/lookups.py,sha256=nVdqNP0uZntgT1czTxuuUMBVhGKbRsKm8RU-YwGt6EE,5362
40
- gisserver/parsers/fes20/operators.py,sha256=E5sdepKSxKmklDfHZoNwBwPCqihx5RQJfiA91bv_Hxc,31196
41
- gisserver/parsers/fes20/sorting.py,sha256=MZXT2RCRKWO9368lkbCbd17IIlTHKuRroafAQVNQuXo,4769
42
- gisserver/parsers/gml/__init__.py,sha256=DS6CRpFayQp3i5UdwdnAenBb6V6B8vSkn4zQmpo-pBM,1573
43
- gisserver/parsers/gml/base.py,sha256=hyYAVg-pagH43MFvVgLBzPbIY-uAR1ytDPCtNaXLeww,1165
44
- gisserver/parsers/gml/geometries.py,sha256=DSBwzjsT16iwSH-bPixLmB5LWpNNUVBL0byl3iMN_Eg,4654
45
- gisserver/parsers/ows/__init__.py,sha256=0SeM6vfwjWI-WeRD7eS_iN4Jsl8uzXr2yMFpZVHokb4,624
46
- gisserver/parsers/ows/kvp.py,sha256=et-vlI3EjcK_z1ArGt26RxDyipuwI85NNDe0FVcg7eI,7093
47
- gisserver/parsers/ows/requests.py,sha256=TZRPX_4RGeNX0qN-OJiRZMGYIWfbn-4vF7zVL4Z1nSk,5496
48
- gisserver/parsers/wfs20/__init__.py,sha256=6_0TZcLVu48J7Pz802CvkrzEoDDIlI7Bz1t7_VPaOjs,881
49
- gisserver/parsers/wfs20/adhoc.py,sha256=yM88MrGudYz692QZTL5H6KO1KKZHg0DL44NKWezbYxU,9066
50
- gisserver/parsers/wfs20/base.py,sha256=_yEIJLrkzPxxj8sjePeSn8PA6L4PTnon5UruDWXejBo,5601
51
- gisserver/parsers/wfs20/projection.py,sha256=iGpg75VnHj3GrFnSJodEuXbhCF04Phh1IfcAFpurkfw,3930
52
- gisserver/parsers/wfs20/requests.py,sha256=fl7CUHrqhnEm__M67CHG3hVB9c2r7jFTHJIqlVbW8fI,16756
53
- gisserver/parsers/wfs20/stored.py,sha256=4YtlildS_lUnY2iZyGQiVQM9TkSjgaaD7iDWtumg82c,7090
54
- gisserver/static/gisserver/index.css,sha256=h24POXHqJOWtcBRNBFMxZiiknbATRTRWCL6nPyTgPr0,440
55
- gisserver/templates/gisserver/index.html,sha256=Gq6nasptfquoyd7ihKLtj02tyadijK_Qh8ies6pZxy8,920
56
- gisserver/templates/gisserver/service_description.html,sha256=y61iVhrcjg44qp-EymaFkUwdsB0LeYTGTbFO0JYOCEs,932
57
- gisserver/templates/gisserver/wfs/feature_field.html,sha256=Kzbs96GcallCdGLeTPYsFnT6wJ5ar-feyqAmHzJT0u8,587
58
- gisserver/templates/gisserver/wfs/feature_type.html,sha256=pIfa1cMsTlNIrzNiEOaq9LjzzF7_vZ9C7eN6KDBLOHE,788
59
- gisserver/templates/gisserver/wfs/2.0.0/get_capabilities.xml,sha256=SGZSn7cDU_Oai6d45xrkqhax5CPyI1oIc8BZLOEw1X4,8695
60
- gisserver/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
- gisserver/templatetags/gisserver_tags.py,sha256=L2YG-PxiKR0QWBMRLLrL_VR94p6wCb5HzgnrPMg4hug,995
62
- django_gisserver-2.0.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
63
- django_gisserver-2.0.dist-info/METADATA,sha256=c9OYER5wjNqHxdxWRA3E3F-v5QMDqPvZ-yCM0NRlFMk,6217
64
- django_gisserver-2.0.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
65
- django_gisserver-2.0.dist-info/top_level.txt,sha256=8zFCEMmkpixE4TPiOAlxSq3PD2EXvAeFKwG4yZoIIOQ,10
66
- django_gisserver-2.0.dist-info/RECORD,,