django-gisserver 1.4.0__py3-none-any.whl → 1.5.0__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 (38) hide show
  1. {django_gisserver-1.4.0.dist-info → django_gisserver-1.5.0.dist-info}/METADATA +15 -13
  2. django_gisserver-1.5.0.dist-info/RECORD +54 -0
  3. {django_gisserver-1.4.0.dist-info → django_gisserver-1.5.0.dist-info}/WHEEL +1 -1
  4. gisserver/__init__.py +1 -1
  5. gisserver/db.py +14 -20
  6. gisserver/exceptions.py +23 -9
  7. gisserver/features.py +64 -100
  8. gisserver/geometries.py +2 -2
  9. gisserver/operations/base.py +31 -21
  10. gisserver/operations/wfs20.py +44 -38
  11. gisserver/output/__init__.py +2 -1
  12. gisserver/output/base.py +43 -27
  13. gisserver/output/csv.py +38 -33
  14. gisserver/output/geojson.py +43 -51
  15. gisserver/output/gml32.py +88 -67
  16. gisserver/output/results.py +23 -8
  17. gisserver/output/utils.py +18 -2
  18. gisserver/output/xmlschema.py +1 -1
  19. gisserver/parsers/base.py +2 -2
  20. gisserver/parsers/fes20/__init__.py +18 -0
  21. gisserver/parsers/fes20/expressions.py +7 -12
  22. gisserver/parsers/fes20/functions.py +1 -1
  23. gisserver/parsers/fes20/operators.py +7 -3
  24. gisserver/parsers/fes20/query.py +11 -1
  25. gisserver/parsers/fes20/sorting.py +3 -1
  26. gisserver/parsers/gml/base.py +1 -1
  27. gisserver/queries/__init__.py +3 -0
  28. gisserver/queries/adhoc.py +16 -12
  29. gisserver/queries/base.py +76 -36
  30. gisserver/queries/projection.py +240 -0
  31. gisserver/queries/stored.py +7 -6
  32. gisserver/templates/gisserver/wfs/2.0.0/get_capabilities.xml +2 -2
  33. gisserver/types.py +78 -24
  34. gisserver/views.py +9 -20
  35. django_gisserver-1.4.0.dist-info/RECORD +0 -54
  36. gisserver/output/gml32_lxml.py +0 -612
  37. {django_gisserver-1.4.0.dist-info → django_gisserver-1.5.0.dist-info}/LICENSE +0 -0
  38. {django_gisserver-1.4.0.dist-info → django_gisserver-1.5.0.dist-info}/top_level.txt +0 -0
@@ -97,8 +97,8 @@
97
97
  </ows:Keywords>{% endif %}
98
98
  <DefaultCRS>{{ feature_type.crs }}</DefaultCRS>{% for crs in feature_type.other_crs %}
99
99
  <OtherCRS>{{ crs }}</OtherCRS>{% endfor %}
100
- <OutputFormats>{% for output in feature_output_formats %}
101
- <Format>{{ output }}</Format>{% endfor %}
100
+ <OutputFormats>{% for output in feature_output_formats %}{% if output.in_capabilities %}
101
+ <Format>{{ output }}</Format>{% endif %}{% endfor %}
102
102
  </OutputFormats>
103
103
  {% if BOUNDING_BOX %}{% with bbox=feature_type.get_bounding_box %}{% if bbox %}<ows:WGS84BoundingBox dimensions="2">
104
104
  <ows:LowerCorner>{{ bbox.lower_corner|join:" " }}</ows:LowerCorner>
gisserver/types.py CHANGED
@@ -32,7 +32,7 @@ from dataclasses import dataclass, field
32
32
  from decimal import Decimal as D
33
33
  from enum import Enum
34
34
  from functools import cached_property
35
- from typing import TYPE_CHECKING
35
+ from typing import TYPE_CHECKING, Literal, cast
36
36
 
37
37
  from django.conf import settings
38
38
  from django.contrib.gis.db.models import F, GeometryField
@@ -48,12 +48,7 @@ from django.utils import dateparse
48
48
  from gisserver.exceptions import ExternalParsingError, OperationProcessingFailed
49
49
  from gisserver.geometries import CRS, WGS84 # noqa: F401 / for backwards compatibility
50
50
 
51
- try:
52
- from typing import Literal # Python 3.8
53
-
54
- _unbounded = Literal["unbounded"]
55
- except ImportError:
56
- _unbounded = str
51
+ _unbounded = Literal["unbounded"]
57
52
 
58
53
  if "django.contrib.postgres" in settings.INSTALLED_APPS:
59
54
  from django.contrib.postgres.fields import ArrayField
@@ -61,6 +56,9 @@ else:
61
56
  ArrayField = None
62
57
 
63
58
  __all__ = [
59
+ "GmlElement",
60
+ "GmlIdAttribute",
61
+ "GmlNameElement",
64
62
  "ORMPath",
65
63
  "XPathMatch",
66
64
  "XsdAnyType",
@@ -167,7 +165,7 @@ class XsdTypes(XsdAnyType, Enum):
167
165
  #: A direct geometry value (used as function argument type)
168
166
  gmlAbstractGeometryType = "gml:AbstractGeometryType"
169
167
 
170
- #: A feature that has an gml:name and gml:boundedBy as possible child element.
168
+ #: A feature that has a gml:name and gml:boundedBy as possible child element.
171
169
  gmlAbstractFeatureType = "gml:AbstractFeatureType"
172
170
  gmlAbstractGMLType = "gml:AbstractGMLType" # base class of gml:AbstractFeatureType
173
171
 
@@ -183,7 +181,7 @@ class XsdTypes(XsdAnyType, Enum):
183
181
 
184
182
  @cached_property
185
183
  def is_geometry(self):
186
- """Whether the value represents a element which contains a GML element."""
184
+ """Whether the value represents an element which contains a GML element."""
187
185
  return self.prefix == "gml" and self.value.endswith("PropertyType")
188
186
 
189
187
  @cached_property
@@ -267,6 +265,10 @@ class XsdNode:
267
265
  #: This supports dot notation to access related attributes.
268
266
  model_attribute: str | None
269
267
 
268
+ #: A link back to the parent that described the featuyre this node is a part of.
269
+ #: This helps to perform additional filtering in side meth:get_value: based on user policies.
270
+ feature_type: FeatureType | None
271
+
270
272
  def __init__(
271
273
  self,
272
274
  name: str,
@@ -275,6 +277,7 @@ class XsdNode:
275
277
  prefix: str | None = "app",
276
278
  source: models.Field | ForeignObjectRel | None = None,
277
279
  model_attribute: str | None = None,
280
+ feature_type: FeatureType | None = None,
278
281
  ):
279
282
  # Using plain assignment instead of dataclass turns out to be needed
280
283
  # for flexibility and easier subclassing.
@@ -283,6 +286,8 @@ class XsdNode:
283
286
  self.prefix = prefix
284
287
  self.source = source
285
288
  self.model_attribute = model_attribute or self.name
289
+ # link back to parent, some get_value() functions need it.
290
+ self.feature_type = feature_type
286
291
 
287
292
  if ":" in self.name:
288
293
  raise ValueError("Use 'prefix' argument for namespaces")
@@ -317,7 +322,7 @@ class XsdNode:
317
322
  if field.value_from_object.__func__ is models.Field.value_from_object:
318
323
  # No custom value_from_object(), this can be fully emulated with attrgetter() too.
319
324
  # Still allow the final node to have a custom attname,
320
- # # which is what Field.value_from_object() does.
325
+ # which is what Field.value_from_object() does.
321
326
  names = model_attribute.split(".")
322
327
  names[-1] = field.attname
323
328
  return operator.attrgetter(".".join(names))
@@ -368,7 +373,7 @@ class XsdNode:
368
373
  """The direct ORM field that provides this property."""
369
374
  if self.model_attribute is None:
370
375
  raise ValueError(f"Node {self.xml_name} has no 'model_attribute' set.")
371
- return self.model_attribute.split(".", 1)[0]
376
+ return self.model_attribute.partition(".")[0]
372
377
 
373
378
  @cached_property
374
379
  def orm_relation(self) -> tuple[str | None, str]:
@@ -376,10 +381,9 @@ class XsdNode:
376
381
  if self.model_attribute is None:
377
382
  raise ValueError(f"Node {self.xml_name} has no 'model_attribute' set.")
378
383
 
379
- try:
380
- path, field = self.model_attribute.rsplit(".", 1)
381
- except ValueError:
382
- return None, self.model_attribute
384
+ path, _, field = self.model_attribute.rpartition(".")
385
+ if not path:
386
+ return None, field
383
387
  else:
384
388
  return path.replace(".", "__"), field
385
389
 
@@ -407,6 +411,8 @@ class XsdNode:
407
411
  if self.is_many and isinstance(value, models.Manager):
408
412
  # Make sure callers can read the individual items by iterating over the value.
409
413
  value = value.all()
414
+ if self.feature_type is not None:
415
+ return self.feature_type.filter_related_queryset(value)
410
416
  return value
411
417
  else:
412
418
  # the _valuegetter() supports value_from_object() on custom fields.
@@ -462,8 +468,8 @@ class XsdNode:
462
468
  and self.source.target_field.get_lookup(lookup) is None
463
469
  ):
464
470
  raise OperationProcessingFailed(
465
- "filter",
466
471
  f"Operator '{tag}' is not supported for the '{self.name}' property.",
472
+ locator="filter",
467
473
  status_code=400, # not HTTP 500 here. Spec allows both.
468
474
  )
469
475
 
@@ -489,7 +495,7 @@ class XsdElement(XsdNode):
489
495
 
490
496
  nillable: bool | None
491
497
  min_occurs: int | None
492
- max_occurs: int | None
498
+ max_occurs: int | _unbounded | None
493
499
 
494
500
  def __init__(
495
501
  self,
@@ -502,8 +508,16 @@ class XsdElement(XsdNode):
502
508
  max_occurs: int | _unbounded | None = None,
503
509
  source: models.Field | ForeignObjectRel | None = None,
504
510
  model_attribute: str | None = None,
511
+ feature_type: FeatureType | None = None,
505
512
  ):
506
- super().__init__(name, type, prefix=prefix, source=source, model_attribute=model_attribute)
513
+ super().__init__(
514
+ name,
515
+ type,
516
+ prefix=prefix,
517
+ source=source,
518
+ model_attribute=model_attribute,
519
+ feature_type=feature_type,
520
+ )
507
521
  self.nillable = nillable
508
522
  self.min_occurs = min_occurs
509
523
  self.max_occurs = max_occurs
@@ -567,11 +581,28 @@ class XsdAttribute(XsdNode):
567
581
  use: str = "optional",
568
582
  source: models.Field | ForeignObjectRel | None = None,
569
583
  model_attribute: str | None = None,
584
+ feature_type: FeatureType | None = None,
570
585
  ):
571
- super().__init__(name, type, prefix=prefix, source=source, model_attribute=model_attribute)
586
+ super().__init__(
587
+ name,
588
+ type,
589
+ prefix=prefix,
590
+ source=source,
591
+ model_attribute=model_attribute,
592
+ feature_type=feature_type,
593
+ )
572
594
  self.use = use
573
595
 
574
596
 
597
+ class GmlElement(XsdElement):
598
+ """Essentially the same as an XsdElement, but guarantee it returns a GeoDjango model field.
599
+
600
+ This only exists as "protocol" for the type annotations.
601
+ """
602
+
603
+ source: GeometryField
604
+
605
+
575
606
  class GmlIdAttribute(XsdAttribute):
576
607
  """A virtual 'gml:id' attribute that can be queried.
577
608
  This subclass has overwritten get_value() logic to format the value.
@@ -584,8 +615,15 @@ class GmlIdAttribute(XsdAttribute):
584
615
  type_name: str,
585
616
  source: models.Field | ForeignObjectRel | None = None,
586
617
  model_attribute="pk",
618
+ feature_type: FeatureType | None = None,
587
619
  ):
588
- super().__init__(prefix="gml", name="id", source=source, model_attribute=model_attribute)
620
+ super().__init__(
621
+ prefix="gml",
622
+ name="id",
623
+ source=source,
624
+ model_attribute=model_attribute,
625
+ feature_type=feature_type,
626
+ )
589
627
  object.__setattr__(self, "type_name", type_name)
590
628
 
591
629
  def get_value(self, instance: models.Model):
@@ -606,6 +644,8 @@ class GmlNameElement(XsdElement):
606
644
  (although that would make comparisons on ``element@gml:name`` more complex).
607
645
  """
608
646
 
647
+ is_geometry = False # Override type
648
+
609
649
  def __init__(
610
650
  self,
611
651
  model_attribute: str,
@@ -620,8 +660,8 @@ class GmlNameElement(XsdElement):
620
660
  min_occurs=0,
621
661
  source=source,
622
662
  model_attribute=model_attribute,
663
+ feature_type=feature_type,
623
664
  )
624
- self.feature_type = feature_type
625
665
 
626
666
  def get_value(self, instance: models.Model):
627
667
  """Override value retrieval to retrieve the value from the feature type."""
@@ -650,8 +690,8 @@ class GmlBoundedByElement(XsdElement):
650
690
  name="boundedBy",
651
691
  type=XsdTypes.gmlBoundingShapeType,
652
692
  min_occurs=0,
693
+ feature_type=feature_type,
653
694
  )
654
- self.feature_type = feature_type
655
695
  self.model_attribute = None
656
696
 
657
697
  def build_lhs_part(self, compiler: CompiledQuery, match: ORMPath):
@@ -735,7 +775,7 @@ class XsdComplexType(XsdAnyType):
735
775
  return self.elements
736
776
 
737
777
  @cached_property
738
- def geometry_elements(self) -> list[XsdElement]:
778
+ def geometry_elements(self) -> list[GmlElement]:
739
779
  """Shortcut to get all geometry elements"""
740
780
  return [e for e in self.elements if e.is_geometry]
741
781
 
@@ -749,6 +789,20 @@ class XsdComplexType(XsdAnyType):
749
789
  """Shortcut to get all elements with a flattened model attribite"""
750
790
  return [e for e in self.elements if e.is_flattened]
751
791
 
792
+ @cached_property
793
+ def elements_with_children(self) -> dict[_XsdElement_WithComplexType, list[XsdElement]]:
794
+ """Shortcut to get all elements with children.
795
+ This mainly exists to provide a structure to mimic what's used
796
+ when PROPERTYNAME is part of the request.
797
+ """
798
+ child_nodes = {}
799
+ for xsd_element in self.elements:
800
+ if xsd_element.type.is_complex_type:
801
+ sub_type = cast(XsdComplexType, xsd_element.type)
802
+ child_nodes[xsd_element] = sub_type.elements
803
+ child_nodes.update(sub_type.elements_with_children)
804
+ return child_nodes
805
+
752
806
  def resolve_element_path(self, xpath: str) -> list[XsdNode] | None:
753
807
  """Resolve a xpath reference to the actual node.
754
808
  This returns the whole path, including in-between relations, if a match was found.
@@ -884,7 +938,7 @@ class ORMPath:
884
938
  class XPathMatch(ORMPath):
885
939
  """The ORM path result from am XPath query.
886
940
 
887
- This result object defines how to resolve an XPath to a ORM object.
941
+ This result object defines how to resolve an XPath to an ORM object.
888
942
  """
889
943
 
890
944
  #: The matched element, with all it's parents.
gisserver/views.py CHANGED
@@ -7,7 +7,6 @@ from urllib.parse import urlencode
7
7
 
8
8
  from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
9
9
  from django.core.exceptions import PermissionDenied as Django_PermissionDenied
10
- from django.http import HttpResponse
11
10
  from django.shortcuts import render
12
11
  from django.views import View
13
12
 
@@ -49,7 +48,7 @@ class GISView(View):
49
48
  #: Metadata of the service:
50
49
  service_description: ServiceDescription | None = None
51
50
 
52
- #: Template to render a HTML welcome page for non-OGC requests.
51
+ #: Template to render an HTML welcome page for non-OGC requests.
53
52
  index_template_name = None
54
53
 
55
54
  #: Whether to render GET HTML pages
@@ -70,22 +69,12 @@ class GISView(View):
70
69
  When nothing is returned, the exception is raised instead.
71
70
  """
72
71
  if isinstance(exc, Django_PermissionDenied):
73
- exc = PermissionDenied("typeNames", text=str(exc) or None)
74
- return HttpResponse(
75
- exc.as_xml().encode("utf-8"),
76
- content_type="text/xml; charset=utf-8",
77
- status=exc.status_code,
78
- reason=exc.reason,
79
- )
72
+ exc = PermissionDenied(str(exc) or None, locator="typeNames")
73
+ return exc.as_response()
80
74
  elif isinstance(exc, OWSException):
81
75
  # Wrap our XML-based exception into a response.
82
76
  exc.version = self.version # Use negotiated version
83
- return HttpResponse(
84
- exc.as_xml().encode("utf-8"),
85
- content_type="text/xml; charset=utf-8",
86
- status=exc.status_code,
87
- reason=exc.reason,
88
- )
77
+ return exc.as_response()
89
78
  else:
90
79
  return None
91
80
 
@@ -106,7 +95,7 @@ class GISView(View):
106
95
  if version and version in self.accept_versions:
107
96
  self.set_version(version)
108
97
 
109
- # Allow for an user-friendly opening page (hence the version check above)
98
+ # Allow for a user-friendly opening page (hence the version check above)
110
99
  if self.use_html_templates and self.is_index_request():
111
100
  return self.render_index()
112
101
 
@@ -192,12 +181,12 @@ class GISView(View):
192
181
  except KeyError:
193
182
  allowed = ", ".join(sorted(self.accept_operations.keys()))
194
183
  raise InvalidParameterValue(
195
- "service",
196
184
  f"'{service}' is an invalid service, supported are: {allowed}.",
185
+ locator="service",
197
186
  ) from None
198
187
 
199
188
  # Resolve the operation
200
- # In mapserver, the operation name is case insensitive.
189
+ # In mapserver, the operation name is case-insensitive.
201
190
  operation = self._get_required_arg("REQUEST").upper()
202
191
  uc_methods = {name.upper(): method for name, method in operations.items()}
203
192
 
@@ -206,8 +195,8 @@ class GISView(View):
206
195
  except KeyError:
207
196
  allowed = ", ".join(operations.keys())
208
197
  raise OperationNotSupported(
209
- "request",
210
198
  f"'{operation.lower()}' is not implemented, supported are: {allowed}.",
199
+ locator="request",
211
200
  ) from None
212
201
 
213
202
  def call_operation(self, wfs_method_cls: type[base.WFSMethod]):
@@ -222,7 +211,7 @@ class GISView(View):
222
211
  except KeyError:
223
212
  if default is not None:
224
213
  return default
225
- raise MissingParameterValue(argname.lower()) from None
214
+ raise MissingParameterValue(locator=argname.lower()) from None
226
215
 
227
216
  def get_service_description(self, service: str) -> ServiceDescription:
228
217
  """Provide the (dynamically generated) service description."""
@@ -1,54 +0,0 @@
1
- gisserver/__init__.py,sha256=1wL_wMnXemLUlKv4XAjjWAY0a7Znc6c7RjHQGuw90VQ,40
2
- gisserver/conf.py,sha256=3LSfeDRTdJCLuopAOD14Y5m2iPhovreIaNI9zbaukpo,2343
3
- gisserver/db.py,sha256=iuj43NonqNdKkLrerdzTucy-Lu5NmqymuE0bkwR6XWs,5318
4
- gisserver/exceptions.py,sha256=TZVdmwKI90Ga-9l8A1H0u65V5yNvgg2TDgyN_LCQ2zI,4597
5
- gisserver/features.py,sha256=CHLCJoQj2dX9SMaBw-akkh8khgDFFqmF_prdIQXf7CU,32089
6
- gisserver/geometries.py,sha256=VQVEFk0oRiqdxG28llb51aayf5m9cbyLljR3PrZfMTg,12400
7
- gisserver/types.py,sha256=vyHPkUXEADikTJfRq7Nodqt0BCo7YV91dNyZw6GIMO4,35087
8
- gisserver/views.py,sha256=A7TwUsG8NKdnjTbOXPbio1K-XRg6IIpy_xH__zwW8xI,13193
9
- gisserver/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- gisserver/operations/base.py,sha256=tIEvQvFRRX2esfeP48EmcwB27-MkShtjl6A1v9TJASE,16827
11
- gisserver/operations/wfs20.py,sha256=lYkEq4DZYTSxNdwdZBAGOb7vtN5qMnwxOp8OD1G3jR4,18426
12
- gisserver/output/__init__.py,sha256=EVzgFN-PqKZKwbGVgWBUbIzGIXo69HSDMQ37szgr6cw,2097
13
- gisserver/output/base.py,sha256=NYyV78JgNDV7uUmnk6HNbbLTkt_N60YKPh2z1o-AuzM,7791
14
- gisserver/output/csv.py,sha256=7UKnyhFyAH1yeOh719Ov3SkzoLF1Zzlp_0-wxRDU9bI,6222
15
- gisserver/output/geojson.py,sha256=KB4w6DU_Dn7ZNDM5INDEtz7zhOAN75v03lUayPDzGPE,11296
16
- gisserver/output/gml32.py,sha256=kaTljrRKIlxIshiJTtzmsWWJExzQSL4hEX_Q1i17k_4,30496
17
- gisserver/output/gml32_lxml.py,sha256=u1aJPdbyVHha9vw7XN2rvD_lvyJZ9zVV3afdcN5Ryf8,25166
18
- gisserver/output/results.py,sha256=HOmeSKLb0Tzsd9AamuXEPZyRmoXxHj7fKBqIbk1J5Co,13301
19
- gisserver/output/utils.py,sha256=VR8nOAv1obhfumQy77RnpJpE3FopzuIJrkfosBq16w4,6569
20
- gisserver/output/xmlschema.py,sha256=ltCglrQ4YXJ_dpMrkXb06dFfHc5a_nGog7fb-K25aeQ,4579
21
- gisserver/parsers/__init__.py,sha256=g72D8EtR-QkhcemzY5-Qty-nhHPKza83Sz3KZm8bfq0,290
22
- gisserver/parsers/base.py,sha256=eK32lw004v-lU82JihnH5LF-3wSh8M-L4JSayDt2gJM,4835
23
- gisserver/parsers/tags.py,sha256=NyJhbt-U2zTewfhghH4LRslTaDK2UOq9Vgk83pWfJh0,3553
24
- gisserver/parsers/values.py,sha256=ypNPl4HduiVzexsL59ukZntlwXk5gHuSvQO6yhLeXD4,1016
25
- gisserver/parsers/fes20/__init__.py,sha256=l8OutRicZ8E2cpyFtJj6wTFNArYoFaLiXABGyZYyKvQ,624
26
- gisserver/parsers/fes20/expressions.py,sha256=kXfIpOP94WOzvT3PZyIKrZSawQJZUPYyJ1TF5MoKsUQ,9694
27
- gisserver/parsers/fes20/filters.py,sha256=HdWguZvAT2L4Xm-bNa4XPh7MEymqTB6fo8r47Z-Bjuw,3511
28
- gisserver/parsers/fes20/functions.py,sha256=Qn72GI5qLqDSbREmsGUDiAPN2u1eo4c8AFttJMDnJX4,8724
29
- gisserver/parsers/fes20/identifiers.py,sha256=vcPrMYcsemSlB9ziSUdVulhoI5PGFAh8vqeADBCWd60,2864
30
- gisserver/parsers/fes20/operators.py,sha256=MVyoo2Hq45Lyqjh1cX9P_Zy9ARceCs28xDNL5ql_Yd0,23206
31
- gisserver/parsers/fes20/query.py,sha256=IQU0k4ZG-sAjWEWvSXw6H_wYODwtCMsF8RrbVdik4KE,10069
32
- gisserver/parsers/fes20/sorting.py,sha256=y0QJxFE0OC-GsaqrD0ZCI4CI16roUZrSW3fAG7BOKwA,2146
33
- gisserver/parsers/gml/__init__.py,sha256=lNK0SXWkmTKdeJD9xdK6B-N-Y7wwGL4NRBI3dzoJDNI,1463
34
- gisserver/parsers/gml/base.py,sha256=cMyXAoc1mhLp3Dqf1f65gNBhjETQWyUx--AHPsPCwBU,1066
35
- gisserver/parsers/gml/geometries.py,sha256=cgV3WogA7LyC_H_NF7dGoGLvLdQRACG6AlThRkX_jhU,3171
36
- gisserver/queries/__init__.py,sha256=zBLHOWKcU7PvBj6NHfGqcdUKCFJdL_np3_Mdn3bx-nE,893
37
- gisserver/queries/adhoc.py,sha256=hhLh3xB0UU--2tZwRgOWzonrjHM8OxCF2YYbl7NsxhE,7087
38
- gisserver/queries/base.py,sha256=w0hXefxX516oN3qdPYvM7huTewqrwxJmAseHHJ_BOgk,5891
39
- gisserver/queries/stored.py,sha256=RasXxlHlMCFtpO3EjIeMH6XPaDNvWbqJP23itR_byuU,7060
40
- gisserver/static/gisserver/index.css,sha256=fiQuCMuiWUhhrNQD6bbUJaX5vH5OpG9qgPdELPB8cpI,163
41
- gisserver/templates/gisserver/index.html,sha256=yliku8jDqAOcenkbe1YnvJBnuS13MvzzsoDV8sQZ3GM,866
42
- gisserver/templates/gisserver/service_description.html,sha256=3EHLnQx27_nTDZFD2RH6E10EWnTN90s1DGuEj9PeBrg,993
43
- gisserver/templates/gisserver/wfs/feature_field.html,sha256=H5LsTAxGVGQqEpOZdEUTszQmFAZSpB9ggRJUsTdjYnw,538
44
- gisserver/templates/gisserver/wfs/feature_type.html,sha256=pIfa1cMsTlNIrzNiEOaq9LjzzF7_vZ9C7eN6KDBLOHE,788
45
- gisserver/templates/gisserver/wfs/2.0.0/describe_stored_queries.xml,sha256=4Hxw1kCnxfWXTVPbHf8IW9_qiSeIEtnxHK6z6TS3-zA,1041
46
- gisserver/templates/gisserver/wfs/2.0.0/get_capabilities.xml,sha256=KKrI0YYQqZWtTOyOkm-ZHuNyfwipdx0i0N8p7fggPU8,8675
47
- gisserver/templates/gisserver/wfs/2.0.0/list_stored_queries.xml,sha256=CIBVQrKXmGMQ6BKbX4_0ru4lXtWnW5EIgHUbIi1V0Vc,636
48
- gisserver/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- gisserver/templatetags/gisserver_tags.py,sha256=RFGqEj-EQi9FrJiFJ7HHAQqlU4fDKVKTtZrPNwURXgA,204
50
- django_gisserver-1.4.0.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
51
- django_gisserver-1.4.0.dist-info/METADATA,sha256=RRLvBRXtqpjAPzlSDFQl0T19KL01QqrlgoclOM_3Ybw,5795
52
- django_gisserver-1.4.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
53
- django_gisserver-1.4.0.dist-info/top_level.txt,sha256=8zFCEMmkpixE4TPiOAlxSq3PD2EXvAeFKwG4yZoIIOQ,10
54
- django_gisserver-1.4.0.dist-info/RECORD,,