django-gisserver 1.3.0__py3-none-any.whl → 1.4.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.
- {django_gisserver-1.3.0.dist-info → django_gisserver-1.4.0.dist-info}/METADATA +12 -15
- django_gisserver-1.4.0.dist-info/RECORD +54 -0
- {django_gisserver-1.3.0.dist-info → django_gisserver-1.4.0.dist-info}/WHEEL +1 -1
- gisserver/__init__.py +1 -1
- gisserver/conf.py +9 -12
- gisserver/db.py +6 -10
- gisserver/exceptions.py +1 -0
- gisserver/features.py +18 -29
- gisserver/geometries.py +11 -25
- gisserver/operations/base.py +19 -40
- gisserver/operations/wfs20.py +8 -20
- gisserver/output/__init__.py +7 -2
- gisserver/output/base.py +4 -13
- gisserver/output/csv.py +13 -16
- gisserver/output/geojson.py +14 -17
- gisserver/output/gml32.py +309 -281
- gisserver/output/gml32_lxml.py +612 -0
- gisserver/output/results.py +105 -22
- gisserver/output/utils.py +15 -5
- gisserver/output/xmlschema.py +7 -8
- gisserver/parsers/base.py +2 -4
- gisserver/parsers/fes20/expressions.py +6 -13
- gisserver/parsers/fes20/filters.py +6 -5
- gisserver/parsers/fes20/functions.py +4 -4
- gisserver/parsers/fes20/identifiers.py +1 -0
- gisserver/parsers/fes20/operators.py +16 -43
- gisserver/parsers/fes20/query.py +1 -3
- gisserver/parsers/fes20/sorting.py +1 -3
- gisserver/parsers/gml/__init__.py +1 -0
- gisserver/parsers/gml/base.py +1 -0
- gisserver/parsers/values.py +1 -3
- gisserver/queries/__init__.py +1 -0
- gisserver/queries/adhoc.py +3 -6
- gisserver/queries/base.py +2 -6
- gisserver/queries/stored.py +3 -6
- gisserver/types.py +59 -46
- gisserver/views.py +7 -10
- django_gisserver-1.3.0.dist-info/RECORD +0 -54
- gisserver/output/buffer.py +0 -64
- {django_gisserver-1.3.0.dist-info → django_gisserver-1.4.0.dist-info}/LICENSE +0 -0
- {django_gisserver-1.3.0.dist-info → django_gisserver-1.4.0.dist-info}/top_level.txt +0 -0
gisserver/queries/adhoc.py
CHANGED
|
@@ -5,6 +5,7 @@ such as the "FILTER", "BBOX" and "RESOURCEID" parameters.
|
|
|
5
5
|
|
|
6
6
|
These definitions follow the WFS spec.
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
10
11
|
import logging
|
|
@@ -95,9 +96,7 @@ class AdhocQuery(QueryExpression):
|
|
|
95
96
|
if id_type_names:
|
|
96
97
|
# Only test when the RESOURCEID has a typename.id format
|
|
97
98
|
# Otherwise, this breaks the CITE RESOURCEID=test-UUID parameter.
|
|
98
|
-
kvp_type_names = {
|
|
99
|
-
feature_type.name for feature_type in params["typeNames"]
|
|
100
|
-
}
|
|
99
|
+
kvp_type_names = {feature_type.name for feature_type in params["typeNames"]}
|
|
101
100
|
if not kvp_type_names.issuperset(id_type_names):
|
|
102
101
|
raise InvalidParameterValue(
|
|
103
102
|
"resourceID",
|
|
@@ -133,9 +132,7 @@ class AdhocQuery(QueryExpression):
|
|
|
133
132
|
def get_type_names(self):
|
|
134
133
|
return self.typeNames
|
|
135
134
|
|
|
136
|
-
def compile_query(
|
|
137
|
-
self, feature_type: FeatureType, using=None
|
|
138
|
-
) -> fes20.CompiledQuery:
|
|
135
|
+
def compile_query(self, feature_type: FeatureType, using=None) -> fes20.CompiledQuery:
|
|
139
136
|
"""Return our internal CompiledQuery object that can be applied to the queryset."""
|
|
140
137
|
if self.filter:
|
|
141
138
|
# Generate the internal query object from the <fes:Filter>
|
gisserver/queries/base.py
CHANGED
|
@@ -69,9 +69,7 @@ class QueryExpression:
|
|
|
69
69
|
results=[
|
|
70
70
|
# Include empty feature collections,
|
|
71
71
|
# so the selected feature types are still known.
|
|
72
|
-
SimpleFeatureCollection(
|
|
73
|
-
feature_type=ft, queryset=qs.none(), start=0, stop=0
|
|
74
|
-
)
|
|
72
|
+
SimpleFeatureCollection(feature_type=ft, queryset=qs.none(), start=0, stop=0)
|
|
75
73
|
for ft, qs in querysets
|
|
76
74
|
],
|
|
77
75
|
number_matched=sum(qs.count() for ft, qs in querysets),
|
|
@@ -139,9 +137,7 @@ class QueryExpression:
|
|
|
139
137
|
f"{self.__class__.__name__}.get_type_names() should be implemented."
|
|
140
138
|
)
|
|
141
139
|
|
|
142
|
-
def compile_query(
|
|
143
|
-
self, feature_type: FeatureType, using=None
|
|
144
|
-
) -> fes20.CompiledQuery:
|
|
140
|
+
def compile_query(self, feature_type: FeatureType, using=None) -> fes20.CompiledQuery:
|
|
145
141
|
"""Define the compiled query that filters the queryset.
|
|
146
142
|
|
|
147
143
|
Subclasses need to define this method, unless
|
gisserver/queries/stored.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
These definitions follow the WFS spec.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from __future__ import annotations
|
|
6
7
|
|
|
7
8
|
from dataclasses import dataclass
|
|
@@ -131,9 +132,7 @@ class StoredQueryParameter(Parameter):
|
|
|
131
132
|
"""Special parameter parsing for the 'STOREDQUERY_ID' parameter"""
|
|
132
133
|
|
|
133
134
|
def __init__(self):
|
|
134
|
-
super().__init__(
|
|
135
|
-
name="STOREDQUERY_ID", parser=stored_query_registry.resolve_query
|
|
136
|
-
)
|
|
135
|
+
super().__init__(name="STOREDQUERY_ID", parser=stored_query_registry.resolve_query)
|
|
137
136
|
|
|
138
137
|
def value_from_query(self, KVP: dict):
|
|
139
138
|
"""Customize the request parsing to read custom parameters too."""
|
|
@@ -199,9 +198,7 @@ class GetFeatureById(StoredQuery):
|
|
|
199
198
|
|
|
200
199
|
return collection
|
|
201
200
|
|
|
202
|
-
def compile_query(
|
|
203
|
-
self, feature_type: FeatureType, using=None
|
|
204
|
-
) -> fes20.CompiledQuery:
|
|
201
|
+
def compile_query(self, feature_type: FeatureType, using=None) -> fes20.CompiledQuery:
|
|
205
202
|
"""Create the internal query object that will be applied to the queryset."""
|
|
206
203
|
compiler = fes20.CompiledQuery(feature_type=feature_type)
|
|
207
204
|
compiler.add_lookups(Q(pk=self.id), type_name=self.type_name)
|
gisserver/types.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Internal XSD type definitions.
|
|
2
2
|
|
|
3
|
-
These types are the internal schema definition
|
|
3
|
+
These types are the internal schema definition, and the foundation for all output generation.
|
|
4
4
|
|
|
5
5
|
The end-users of this library typically create a WFS feature type definition by using
|
|
6
6
|
the :class:~gisserver.features.FeatureType` / :class:`~gisserver.features.FeatureField` classes.
|
|
@@ -23,6 +23,7 @@ Each XMLSchema node defines it's "data type" as either:
|
|
|
23
23
|
|
|
24
24
|
Custom field types could also generate these field types.
|
|
25
25
|
"""
|
|
26
|
+
|
|
26
27
|
from __future__ import annotations
|
|
27
28
|
|
|
28
29
|
import operator
|
|
@@ -30,6 +31,7 @@ import re
|
|
|
30
31
|
from dataclasses import dataclass, field
|
|
31
32
|
from decimal import Decimal as D
|
|
32
33
|
from enum import Enum
|
|
34
|
+
from functools import cached_property
|
|
33
35
|
from typing import TYPE_CHECKING
|
|
34
36
|
|
|
35
37
|
from django.conf import settings
|
|
@@ -42,7 +44,6 @@ from django.db.models.fields.related import ( # Django 2 imports
|
|
|
42
44
|
RelatedField,
|
|
43
45
|
)
|
|
44
46
|
from django.utils import dateparse
|
|
45
|
-
from django.utils.functional import cached_property
|
|
46
47
|
|
|
47
48
|
from gisserver.exceptions import ExternalParsingError, OperationProcessingFailed
|
|
48
49
|
from gisserver.geometries import CRS, WGS84 # noqa: F401 / for backwards compatibility
|
|
@@ -146,7 +147,7 @@ class XsdTypes(XsdAnyType, Enum):
|
|
|
146
147
|
gYear = "gYear"
|
|
147
148
|
hexBinary = "hexBinary"
|
|
148
149
|
base64Binary = "base64Binary"
|
|
149
|
-
token = "token"
|
|
150
|
+
token = "token" # noqa: S105
|
|
150
151
|
language = "language"
|
|
151
152
|
|
|
152
153
|
# Types that contain a GML value as member:
|
|
@@ -193,9 +194,7 @@ class XsdTypes(XsdAnyType, Enum):
|
|
|
193
194
|
try:
|
|
194
195
|
return TYPES_TO_PYTHON[self]
|
|
195
196
|
except KeyError:
|
|
196
|
-
raise NotImplementedError(
|
|
197
|
-
f'Casting to "{self}" is not implemented.'
|
|
198
|
-
) from None
|
|
197
|
+
raise NotImplementedError(f'Casting to "{self}" is not implemented.') from None
|
|
199
198
|
|
|
200
199
|
def to_python(self, raw_value):
|
|
201
200
|
"""Convert a raw string value to this type representation"""
|
|
@@ -219,7 +218,9 @@ def _init_types_to_python():
|
|
|
219
218
|
global TYPES_TO_PYTHON
|
|
220
219
|
from gisserver.parsers import values # avoid cyclic import
|
|
221
220
|
|
|
222
|
-
as_is
|
|
221
|
+
def as_is(v):
|
|
222
|
+
return v
|
|
223
|
+
|
|
223
224
|
TYPES_TO_PYTHON = {
|
|
224
225
|
XsdTypes.date: dateparse.parse_date,
|
|
225
226
|
XsdTypes.dateTime: values.parse_iso_datetime,
|
|
@@ -300,29 +301,40 @@ class XsdNode:
|
|
|
300
301
|
model_attribute: str,
|
|
301
302
|
field: models.Field | ForeignObjectRel | None,
|
|
302
303
|
):
|
|
303
|
-
"""Select the most efficient read function to retrieves the value.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
304
|
+
"""Select the most efficient read function to retrieves the value.
|
|
305
|
+
|
|
306
|
+
Since reading a value can be called like 150000+ times, this is heavily optimized.
|
|
307
|
+
|
|
308
|
+
This attempts to use ``operator.attrgetter()`` whenever possible,
|
|
309
|
+
since this will be much faster than using ``getattr()``.
|
|
310
|
+
The custom ``value_from_object()`` is fully supported too.
|
|
311
|
+
"""
|
|
312
|
+
if field is None or isinstance(field, ForeignObjectRel):
|
|
313
|
+
# No model field, can only use getattr(). The attrgetter() function is both faster,
|
|
314
|
+
# and has built-in support for traversing model attributes with dots.
|
|
310
315
|
return operator.attrgetter(model_attribute)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
#
|
|
314
|
-
#
|
|
315
|
-
|
|
316
|
-
else:
|
|
317
|
-
# Need to traverse foreign key relations before using value_from_objec().
|
|
316
|
+
|
|
317
|
+
if field.value_from_object.__func__ is models.Field.value_from_object:
|
|
318
|
+
# No custom value_from_object(), this can be fully emulated with attrgetter() too.
|
|
319
|
+
# Still allow the final node to have a custom attname,
|
|
320
|
+
# # which is what Field.value_from_object() does.
|
|
318
321
|
names = model_attribute.split(".")
|
|
322
|
+
names[-1] = field.attname
|
|
323
|
+
return operator.attrgetter(".".join(names))
|
|
324
|
+
|
|
325
|
+
if "." not in model_attribute:
|
|
326
|
+
# Single level, use the custom value_from_object() directly.
|
|
327
|
+
return field.value_from_object
|
|
328
|
+
|
|
329
|
+
# Need to traverse the related field path, and use value_from_object() on the final object.
|
|
330
|
+
names = model_attribute.split(".")
|
|
331
|
+
get_related_instance = operator.attrgetter(".".join(names[:-1]))
|
|
319
332
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
return field.value_from_object(instance)
|
|
333
|
+
def _related_get_value_from_object(instance):
|
|
334
|
+
related_instance = get_related_instance(instance)
|
|
335
|
+
return field.value_from_object(related_instance)
|
|
324
336
|
|
|
325
|
-
|
|
337
|
+
return _related_get_value_from_object
|
|
326
338
|
|
|
327
339
|
@cached_property
|
|
328
340
|
def is_geometry(self) -> bool:
|
|
@@ -397,13 +409,13 @@ class XsdNode:
|
|
|
397
409
|
value = value.all()
|
|
398
410
|
return value
|
|
399
411
|
else:
|
|
400
|
-
#
|
|
401
|
-
return self.
|
|
412
|
+
# the _valuegetter() supports value_from_object() on custom fields.
|
|
413
|
+
return self._valuegetter(instance)
|
|
402
414
|
except (AttributeError, ObjectDoesNotExist):
|
|
403
415
|
# E.g. Django foreign keys that point to a non-existing member.
|
|
404
416
|
return None
|
|
405
417
|
|
|
406
|
-
def
|
|
418
|
+
def format_raw_value(self, value):
|
|
407
419
|
"""Allow to apply some final transformations on a value.
|
|
408
420
|
This is mainly used to support @gml:id which includes a prefix.
|
|
409
421
|
"""
|
|
@@ -426,9 +438,7 @@ class XsdNode:
|
|
|
426
438
|
code=e.code,
|
|
427
439
|
) from e
|
|
428
440
|
except (ValueError, TypeError) as e:
|
|
429
|
-
raise ValidationError(
|
|
430
|
-
f"Invalid data for the '{self.name}' property: {e}"
|
|
431
|
-
) from e
|
|
441
|
+
raise ValidationError(f"Invalid data for the '{self.name}' property: {e}") from e
|
|
432
442
|
|
|
433
443
|
return raw_value
|
|
434
444
|
|
|
@@ -493,9 +503,7 @@ class XsdElement(XsdNode):
|
|
|
493
503
|
source: models.Field | ForeignObjectRel | None = None,
|
|
494
504
|
model_attribute: str | None = None,
|
|
495
505
|
):
|
|
496
|
-
super().__init__(
|
|
497
|
-
name, type, prefix=prefix, source=source, model_attribute=model_attribute
|
|
498
|
-
)
|
|
506
|
+
super().__init__(name, type, prefix=prefix, source=source, model_attribute=model_attribute)
|
|
499
507
|
self.nillable = nillable
|
|
500
508
|
self.min_occurs = min_occurs
|
|
501
509
|
self.max_occurs = max_occurs
|
|
@@ -560,9 +568,7 @@ class XsdAttribute(XsdNode):
|
|
|
560
568
|
source: models.Field | ForeignObjectRel | None = None,
|
|
561
569
|
model_attribute: str | None = None,
|
|
562
570
|
):
|
|
563
|
-
super().__init__(
|
|
564
|
-
name, type, prefix=prefix, source=source, model_attribute=model_attribute
|
|
565
|
-
)
|
|
571
|
+
super().__init__(name, type, prefix=prefix, source=source, model_attribute=model_attribute)
|
|
566
572
|
self.use = use
|
|
567
573
|
|
|
568
574
|
|
|
@@ -579,16 +585,14 @@ class GmlIdAttribute(XsdAttribute):
|
|
|
579
585
|
source: models.Field | ForeignObjectRel | None = None,
|
|
580
586
|
model_attribute="pk",
|
|
581
587
|
):
|
|
582
|
-
super().__init__(
|
|
583
|
-
prefix="gml", name="id", source=source, model_attribute=model_attribute
|
|
584
|
-
)
|
|
588
|
+
super().__init__(prefix="gml", name="id", source=source, model_attribute=model_attribute)
|
|
585
589
|
object.__setattr__(self, "type_name", type_name)
|
|
586
590
|
|
|
587
591
|
def get_value(self, instance: models.Model):
|
|
588
592
|
pk = super().get_value(instance) # handle dotted-name notations
|
|
589
593
|
return f"{self.type_name}.{pk}"
|
|
590
594
|
|
|
591
|
-
def
|
|
595
|
+
def format_raw_value(self, value):
|
|
592
596
|
"""Format the value as retrieved from the database."""
|
|
593
597
|
return f"{self.type_name}.{value}"
|
|
594
598
|
|
|
@@ -671,7 +675,7 @@ class XsdComplexType(XsdAnyType):
|
|
|
671
675
|
|
|
672
676
|
Typically, this maps into a Django model, with each element pointing to a model field.
|
|
673
677
|
|
|
674
|
-
|
|
678
|
+
A complex type can hold multiple :class:`XsdElement` and :class:`XsdAttribute`
|
|
675
679
|
nodes as children, composing an object. The elements themselves can point
|
|
676
680
|
to a complex type themselves, to create a nested class structure.
|
|
677
681
|
That also allows embedding models with their relations into a single response.
|
|
@@ -719,6 +723,17 @@ class XsdComplexType(XsdAnyType):
|
|
|
719
723
|
def is_complex_type(self):
|
|
720
724
|
return True # a property to avoid being used as field.
|
|
721
725
|
|
|
726
|
+
@cached_property
|
|
727
|
+
def all_elements(self) -> list[XsdElement]:
|
|
728
|
+
"""All elements, including inherited elements."""
|
|
729
|
+
if self.base.is_complex_type:
|
|
730
|
+
# Add all base class members, in their correct ordering
|
|
731
|
+
# By having these as XsdElement objects instead of hard-coded writes,
|
|
732
|
+
# the query/filter logic also works for these elements.
|
|
733
|
+
return self.base.elements + self.elements
|
|
734
|
+
else:
|
|
735
|
+
return self.elements
|
|
736
|
+
|
|
722
737
|
@cached_property
|
|
723
738
|
def geometry_elements(self) -> list[XsdElement]:
|
|
724
739
|
"""Shortcut to get all geometry elements"""
|
|
@@ -890,9 +905,7 @@ class XPathMatch(ORMPath):
|
|
|
890
905
|
if "[" in self.query:
|
|
891
906
|
# If there is an element[@attr=...]/field tag,
|
|
892
907
|
# the build_...() logic should return a Q() object.
|
|
893
|
-
raise NotImplementedError(
|
|
894
|
-
f"Complex XPath queries are not supported yet: {self.query}"
|
|
895
|
-
)
|
|
908
|
+
raise NotImplementedError(f"Complex XPath queries are not supported yet: {self.query}")
|
|
896
909
|
|
|
897
910
|
@cached_property
|
|
898
911
|
def orm_path(self) -> str:
|
gisserver/views.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"""The view layer parses the request, and dispatches it to an operation."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
|
|
4
5
|
import re
|
|
5
6
|
from urllib.parse import urlencode
|
|
6
7
|
|
|
7
|
-
from django.core.exceptions import ImproperlyConfigured
|
|
8
|
+
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
|
|
8
9
|
from django.core.exceptions import PermissionDenied as Django_PermissionDenied
|
|
9
|
-
from django.core.exceptions import SuspiciousOperation
|
|
10
10
|
from django.http import HttpResponse
|
|
11
11
|
from django.shortcuts import render
|
|
12
12
|
from django.views import View
|
|
@@ -86,6 +86,8 @@ class GISView(View):
|
|
|
86
86
|
status=exc.status_code,
|
|
87
87
|
reason=exc.reason,
|
|
88
88
|
)
|
|
89
|
+
else:
|
|
90
|
+
return None
|
|
89
91
|
|
|
90
92
|
def get(self, request, *args, **kwargs):
|
|
91
93
|
"""Entry point to handle HTTP GET requests.
|
|
@@ -129,9 +131,7 @@ class GISView(View):
|
|
|
129
131
|
"""Render the index page."""
|
|
130
132
|
# Not using the whole TemplateResponseMixin config with configurable parameters.
|
|
131
133
|
# If this really needs more configuration, overriding is likely just as easy.
|
|
132
|
-
return render(
|
|
133
|
-
self.request, self.get_index_template_names(), self.get_index_context_data()
|
|
134
|
-
)
|
|
134
|
+
return render(self.request, self.get_index_template_names(), self.get_index_context_data())
|
|
135
135
|
|
|
136
136
|
def get_index_context_data(self, **kwargs):
|
|
137
137
|
"""Provide the context data for the index page."""
|
|
@@ -143,8 +143,7 @@ class GISView(View):
|
|
|
143
143
|
base_qs = {
|
|
144
144
|
key: value
|
|
145
145
|
for key, value in self.request.GET.items()
|
|
146
|
-
if key.upper()
|
|
147
|
-
not in ("SERVICE", "REQUEST", "VERSION", "OUTPUTFORMAT", "TYPENAMES")
|
|
146
|
+
if key.upper() not in ("SERVICE", "REQUEST", "VERSION", "OUTPUTFORMAT", "TYPENAMES")
|
|
148
147
|
}
|
|
149
148
|
base_query = urlencode(base_qs) + "&" if base_qs else ""
|
|
150
149
|
|
|
@@ -173,9 +172,7 @@ class GISView(View):
|
|
|
173
172
|
|
|
174
173
|
if self.index_template_name:
|
|
175
174
|
# Allow the same substitutions for a manually configured template.
|
|
176
|
-
return [
|
|
177
|
-
self.index_template_name.format(service=service, version=self.version)
|
|
178
|
-
]
|
|
175
|
+
return [self.index_template_name.format(service=service, version=self.version)]
|
|
179
176
|
else:
|
|
180
177
|
return [
|
|
181
178
|
f"gisserver/{service}/{self.version}/index.html",
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
gisserver/__init__.py,sha256=BfdKG3T6jfPrJ5AF8bDHgTsS70jBTw-Eg3IjeDKAlPQ,40
|
|
2
|
-
gisserver/conf.py,sha256=DC3TNBhA2kcLxTwmzhmrW5Noiv2QsPQms_EAAZLtO-4,2108
|
|
3
|
-
gisserver/db.py,sha256=4NSxzwCLsTON2wrLBKZweg6kOlZelV4fzdsrMGpC7V8,5329
|
|
4
|
-
gisserver/exceptions.py,sha256=kf6o-Vk9CrAAcjk4uGlQVvXnuYOBVks4pcQly3pKRPU,4596
|
|
5
|
-
gisserver/features.py,sha256=XKLs0WrrT-7Hwc2ByUYuOMOInzFONP9KpfGS065mIKI,32232
|
|
6
|
-
gisserver/geometries.py,sha256=PEmYKV8yw1fjwL6ortc1w72UOByRHz88NDEyPuO3qFo,12619
|
|
7
|
-
gisserver/types.py,sha256=dfybev3kq1IO3jaIy9uETOqHwqQOzEG94fKEbQB-AEQ,34202
|
|
8
|
-
gisserver/views.py,sha256=Z55WA8Qc5OpP0ONPMPGqs-66w0ZR9XpDs9fJ8toqda4,13252
|
|
9
|
-
gisserver/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
gisserver/operations/base.py,sha256=XFW9Y9oOHzdPou3cfZQ2UWCZbDba23MBydbN6owfomc,17012
|
|
11
|
-
gisserver/operations/wfs20.py,sha256=J54vnxEE_8Myz5uwnjltElun_H1MvKQNeWZNjIWiDF4,18635
|
|
12
|
-
gisserver/output/__init__.py,sha256=kWdJHxKtQNKK4Bld8uNdVqk3cjgpiagBL_FlMjsbjQc,1950
|
|
13
|
-
gisserver/output/base.py,sha256=W4017N2qlEuPCbXLl17SQUVfTpTZphiSURd75NR9Hac,7954
|
|
14
|
-
gisserver/output/buffer.py,sha256=Jqw94wa1YFcKbFB9ZLiYx2L0TRD1MDZNLF5te3QBqgU,1542
|
|
15
|
-
gisserver/output/csv.py,sha256=sVj1U1dVkMqm-cwjGbnDg-YLQL1QcRMXyH6LqgC7tN4,6179
|
|
16
|
-
gisserver/output/geojson.py,sha256=a8A628p1PEF-fmKdm3CrGDyCRPZdukMZRNzjiqDosWY,11217
|
|
17
|
-
gisserver/output/gml32.py,sha256=_IN5ehNLGPk5z3euIxavukjYsoHn6liPqY__Ge7LpjY,26894
|
|
18
|
-
gisserver/output/results.py,sha256=JdOznMx1xDxSmekMWW5YyF_muzrJXd6DVy0qqs2ewKI,9224
|
|
19
|
-
gisserver/output/utils.py,sha256=fMUPnAKXiT5IX3GlO0amZKzd_8ixNG_g1lgmZ3aNyGo,6113
|
|
20
|
-
gisserver/output/xmlschema.py,sha256=JVYx5ZXeIt4v8HLsEcRg5dR9WcrOREctlGaHcn31rEw,4603
|
|
21
|
-
gisserver/parsers/__init__.py,sha256=g72D8EtR-QkhcemzY5-Qty-nhHPKza83Sz3KZm8bfq0,290
|
|
22
|
-
gisserver/parsers/base.py,sha256=-XI2_ryoZ8tOIgckp71eEiJDoLxCXN2fQK8yY6gKNJ0,4864
|
|
23
|
-
gisserver/parsers/tags.py,sha256=NyJhbt-U2zTewfhghH4LRslTaDK2UOq9Vgk83pWfJh0,3553
|
|
24
|
-
gisserver/parsers/values.py,sha256=YtkP2QFkV6T8vOWcze7b5goydXgzYuwMIjuMFdGRrA4,1038
|
|
25
|
-
gisserver/parsers/fes20/__init__.py,sha256=l8OutRicZ8E2cpyFtJj6wTFNArYoFaLiXABGyZYyKvQ,624
|
|
26
|
-
gisserver/parsers/fes20/expressions.py,sha256=aweq4NnFvbkqe5Ba5zazvkMkpoBZqI0jNeDAG2QYqJE,9747
|
|
27
|
-
gisserver/parsers/fes20/filters.py,sha256=HBiGh_4Ddw3rY5TKxHtXFnkJe_80fbtVvfmR_QVM52Q,3507
|
|
28
|
-
gisserver/parsers/fes20/functions.py,sha256=GWiOmixNXqP2NvZ70GBnRAjqILwpfYKJggVc-LhnsyY,8726
|
|
29
|
-
gisserver/parsers/fes20/identifiers.py,sha256=KRkYj-fWJUZJlde7GY8uG2Ii5f5DERodXbaJMBQg2TQ,2863
|
|
30
|
-
gisserver/parsers/fes20/operators.py,sha256=eZu9Wx2ZTTKpy61FiA3XmO6RzRBhRw78Gxmy69vOmiY,23601
|
|
31
|
-
gisserver/parsers/fes20/query.py,sha256=_jWNfVEiis_JwJwOshPwqRTecm6zJ8Dm5CKssDiKtio,10083
|
|
32
|
-
gisserver/parsers/fes20/sorting.py,sha256=jBz52eaY0-JS6q16D2eGCA5IvvjwlQv3oHsxEFqYsH0,2176
|
|
33
|
-
gisserver/parsers/gml/__init__.py,sha256=4t15m7VxqgOOAh9ybAVEISiZyKaDL4xyBEJfPCil6eA,1462
|
|
34
|
-
gisserver/parsers/gml/base.py,sha256=ct2bl5Q2P9gDtXg4gJcsm02cmc6fiv_x3n0R6IgJfW8,1065
|
|
35
|
-
gisserver/parsers/gml/geometries.py,sha256=cgV3WogA7LyC_H_NF7dGoGLvLdQRACG6AlThRkX_jhU,3171
|
|
36
|
-
gisserver/queries/__init__.py,sha256=HI_J_kv60fc7wYaaNLz7_yeLz-9Y1Q_p7PDmMa2sIiw,892
|
|
37
|
-
gisserver/queries/adhoc.py,sha256=gVgi7cel0pjQo8AyiDOd53qHpFSZxCnXDuMP4N1IXSw,7146
|
|
38
|
-
gisserver/queries/base.py,sha256=-vf6bufYbTDq41PBjoV7N7R9sdPBPta8tKIBVrUY1Nc,5943
|
|
39
|
-
gisserver/queries/stored.py,sha256=ncxiDo-kc5v4WKyPTAd4uOnyFPN-y1N9SW6Zg1Xazvg,7095
|
|
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.3.0.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
51
|
-
django_gisserver-1.3.0.dist-info/METADATA,sha256=N9SdE0qRO4HBR8MW1XiTo45KOvPeFWTA_k3p0q_iH5s,5834
|
|
52
|
-
django_gisserver-1.3.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
|
53
|
-
django_gisserver-1.3.0.dist-info/top_level.txt,sha256=8zFCEMmkpixE4TPiOAlxSq3PD2EXvAeFKwG4yZoIIOQ,10
|
|
54
|
-
django_gisserver-1.3.0.dist-info/RECORD,,
|
gisserver/output/buffer.py
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"""Output buffering, to write data in chunks.
|
|
2
|
-
|
|
3
|
-
This builds on top of StringIO/BytesIO to write data and regularly flush it.
|
|
4
|
-
"""
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import io
|
|
8
|
-
from typing import Generic, TypeVar
|
|
9
|
-
|
|
10
|
-
V = TypeVar("V", str, bytes)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class BaseBuffer(Generic[V]):
|
|
14
|
-
"""Fast buffer to write data in chunks.
|
|
15
|
-
This avoids performing too many yields in the output writing.
|
|
16
|
-
Especially for GeoJSON, that slows down the response times.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
buffer_class = None
|
|
20
|
-
|
|
21
|
-
def __init__(self, chunk_size=8192):
|
|
22
|
-
self.data = self.buffer_class()
|
|
23
|
-
self.chunk_size = chunk_size
|
|
24
|
-
|
|
25
|
-
def is_full(self):
|
|
26
|
-
# Calling data.seek() is faster than doing self.size += len(value)
|
|
27
|
-
# because each integer increment is a new object allocation.
|
|
28
|
-
return self.data.tell() >= self.chunk_size
|
|
29
|
-
|
|
30
|
-
def write(self, value: V):
|
|
31
|
-
if value is None:
|
|
32
|
-
return
|
|
33
|
-
self.data.write(value)
|
|
34
|
-
|
|
35
|
-
def flush(self) -> V:
|
|
36
|
-
"""Empty the buffer and return it."""
|
|
37
|
-
data = self.getvalue()
|
|
38
|
-
self.clear()
|
|
39
|
-
return data
|
|
40
|
-
|
|
41
|
-
def getvalue(self) -> V:
|
|
42
|
-
return self.data.getvalue()
|
|
43
|
-
|
|
44
|
-
def clear(self):
|
|
45
|
-
self.data.seek(0)
|
|
46
|
-
self.data.truncate(0)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class BytesBuffer(BaseBuffer[bytes]):
|
|
50
|
-
"""Collect the data as bytes."""
|
|
51
|
-
|
|
52
|
-
buffer_class = io.BytesIO
|
|
53
|
-
|
|
54
|
-
def __bytes__(self):
|
|
55
|
-
return self.getvalue()
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class StringBuffer(BaseBuffer[str]):
|
|
59
|
-
"""Collect the data as string"""
|
|
60
|
-
|
|
61
|
-
buffer_class = io.StringIO
|
|
62
|
-
|
|
63
|
-
def __str__(self):
|
|
64
|
-
return self.getvalue()
|
|
File without changes
|
|
File without changes
|