• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geopython / OWSLib / 3663701074

pending completion
3663701074

Pull #851

github

GitHub
Merge 6cd54d613 into 13b1443f7
Pull Request #851: Adding Python 3.10 in CI

7461 of 12701 relevant lines covered (58.74%)

0.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.5
/owslib/feature/schema.py
1
# =============================================================================
2
# OWSLib. Copyright (C) 2015 Jachym Cepicky
3
#
4
# Contact email: jachym.cepicky@gmail.com
5
#
6
# =============================================================================
7
"""
1✔
8
Set of functions, which are suitable for DescribeFeatureType parsing and
9
generating layer schema description compatible with `fiona`
10
"""
11

12
import sys
1✔
13
from urllib.parse import urlencode, parse_qsl
1✔
14
from owslib.etree import etree
1✔
15
from owslib.namespaces import Namespaces
1✔
16
from owslib.util import which_etree, findall, Authentication, openURL
1✔
17

18
MYNS = Namespaces()
1✔
19
XS_NAMESPACE = MYNS.get_namespace("xs")
1✔
20
GML_NAMESPACES = (
1✔
21
    MYNS.get_namespace("gml"),
22
    MYNS.get_namespace("gml311"),
23
    MYNS.get_namespace("gml32"),
24
)
25

26

27
def get_schema(
1✔
28
    url, typename, version="1.0.0", timeout=30, headers=None, username=None, password=None, auth=None
29
):
30
    """Parses DescribeFeatureType response and creates schema compatible
31
    with :class:`fiona`
32

33
    :param str url: url of the service
34
    :param str version: version of the service
35
    :param str typename: name of the layer
36
    :param int timeout: request timeout
37
    :param str username: service authentication username
38
    :param str password: service authentication password
39
    :param Authentication auth: instance of owslib.util.Authentication
40
    """
41
    if auth:
1✔
42
        if username:
1✔
43
            auth.username = username
×
44
        if password:
1✔
45
            auth.password = password
×
46
    else:
47
        auth = Authentication(username, password)
×
48
    url = _get_describefeaturetype_url(url, version, typename)
1✔
49
    root = _get_remote_describefeaturetype(url, timeout=timeout,
1✔
50
                                           headers=headers, auth=auth)
51

52
    if ":" in typename:
1✔
53
        typename = typename.split(":")[1]
1✔
54
    type_element = root.find("./{%s}element" % XS_NAMESPACE)
1✔
55
    if type_element is None:
1✔
56
        return None
×
57
    complex_type = type_element.attrib["type"].split(":")[1]
1✔
58
    elements = _get_elements(complex_type, root)
1✔
59
    nsmap = None
1✔
60
    if hasattr(root, "nsmap"):
1✔
61
        nsmap = root.nsmap
×
62
    return _construct_schema(elements, nsmap)
1✔
63

64

65
def _get_elements(complex_type, root):
1✔
66
    """Get attribute elements
67
    """
68

69
    found_elements = []
1✔
70
    element = findall(
1✔
71
        root,
72
        "{%s}complexType" % XS_NAMESPACE,
73
        attribute_name="name",
74
        attribute_value=complex_type,
75
    )[0]
76
    found_elements = findall(element, "{%s}element" % XS_NAMESPACE)
1✔
77

78
    return found_elements
1✔
79

80

81
def _construct_schema(elements, nsmap):
1✔
82
    """Consruct fiona schema based on given elements
83

84
    :param list Element: list of elements
85
    :param dict nsmap: namespace map
86

87
    :return dict: schema
88
    """
89
    if elements is None:
1✔
90
        return None
×
91
    schema = {"properties": {}, "required": [], "geometry": None}
1✔
92

93
    schema_key = None
1✔
94
    gml_key = None
1✔
95

96
    # if nsmap is defined, use it
97
    if nsmap:
1✔
98
        for key in nsmap:
×
99
            if nsmap[key] == XS_NAMESPACE:
×
100
                schema_key = key
×
101
            if nsmap[key] in GML_NAMESPACES:
×
102
                gml_key = key
×
103
    # if no nsmap is defined, we have to guess
104
    else:
105
        gml_key = "gml"
1✔
106
        schema_key = "xsd"
1✔
107

108
    mappings = {
1✔
109
        "PointPropertyType": "Point",
110
        "PolygonPropertyType": "Polygon",
111
        "LineStringPropertyType": "LineString",
112
        "MultiPointPropertyType": "MultiPoint",
113
        "MultiLineStringPropertyType": "MultiLineString",
114
        "MultiPolygonPropertyType": "MultiPolygon",
115
        "MultiGeometryPropertyType": "MultiGeometry",
116
        "GeometryPropertyType": "GeometryCollection",
117
        "SurfacePropertyType": "3D Polygon",
118
        "MultiSurfacePropertyType": "3D MultiPolygon",
119
    }
120

121
    for element in elements:
1✔
122
        data_type = element.attrib["type"].replace(gml_key + ":", "")
1✔
123
        name = element.attrib["name"]
1✔
124
        non_nillable = element.attrib.get("nillable", "false") == "false"
1✔
125

126
        if data_type in mappings:
1✔
127
            schema["geometry"] = mappings[data_type]
1✔
128
            schema["geometry_column"] = name
1✔
129
        else:
130
            if schema_key is not None:
1✔
131
                schema["properties"][name] = data_type.replace(schema_key + ":", "")
1✔
132

133
        if non_nillable:
1✔
134
            schema["required"].append(name)
×
135

136
    if schema["properties"] or schema["geometry"]:
1✔
137
        return schema
1✔
138
    else:
139
        return None
×
140

141

142
def _get_describefeaturetype_url(url, version, typename):
1✔
143
    """Get url for describefeaturetype request
144

145
    :return str: url
146
    """
147

148
    query_string = []
1✔
149
    if url.find("?") != -1:
1✔
150
        query_string = parse_qsl(url.split("?")[1])
×
151

152
    params = [x[0] for x in query_string]
1✔
153

154
    if "service" not in params:
1✔
155
        query_string.append(("service", "WFS"))
1✔
156
    if "request" not in params:
1✔
157
        query_string.append(("request", "DescribeFeatureType"))
1✔
158
    if "version" not in params:
1✔
159
        query_string.append(("version", version))
1✔
160

161
    query_string.append(("typeName", typename))
1✔
162

163
    urlqs = urlencode(tuple(query_string))
1✔
164
    return url.split("?")[0] + "?" + urlqs
1✔
165

166

167
def _get_remote_describefeaturetype(url, timeout, headers, auth):
1✔
168
    """Gets the DescribeFeatureType response from the remote server.
169

170
    :param str url: url of the service
171
    :param int timeout: request timeout
172
    :param Authentication auth: instance of owslib.util.Authentication
173

174
    :return etree.Element with the root of the DescribeFeatureType response
175
    """
176
    res = openURL(url, timeout=timeout, headers=headers, auth=auth)
1✔
177
    return etree.fromstring(res.read())
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc