• 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

83.02
/owslib/ows.py
1
# -*- coding: ISO-8859-15 -*-
2
# =============================================================================
3
# Copyright (c) 2008 Tom Kralidis
4
#
5
# Authors : Tom Kralidis <tomkralidis@gmail.com>
6
#
7
# Contact email: tomkralidis@gmail.com
8
# =============================================================================
9

10
"""
1✔
11
API for OGC Web Services Common (OWS) constructs and metadata.
12

13
OWS Common: http://www.opengeospatial.org/standards/common
14

15
Currently supports version 1.1.0 (06-121r3).
16
"""
17

18
import logging
1✔
19

20
from owslib.etree import etree
1✔
21
from owslib import crs, util
1✔
22
from owslib.namespaces import Namespaces
1✔
23

24
LOGGER = logging.getLogger(__name__)
1✔
25

26
n = Namespaces()
1✔
27

28
OWS_NAMESPACE_1_0_0 = n.get_namespace("ows")
1✔
29
OWS_NAMESPACE_1_1_0 = n.get_namespace("ows110")
1✔
30
OWS_NAMESPACE_2_0_0 = n.get_namespace("ows200")
1✔
31
XSI_NAMESPACE = n.get_namespace("xsi")
1✔
32
XLINK_NAMESPACE = n.get_namespace("xlink")
1✔
33

34
DEFAULT_OWS_NAMESPACE = OWS_NAMESPACE_1_1_0  # Use this as default for OWSCommon objects
1✔
35

36

37
class OwsCommon(object):
1✔
38
    """Initialize OWS Common object"""
39
    def __init__(self, version):
1✔
40
        self.version = version
1✔
41
        if version == '1.0.0':
1✔
42
            self.namespace = OWS_NAMESPACE_1_0_0
1✔
43
        elif version == '1.1.0':
1✔
44
            self.namespace = OWS_NAMESPACE_1_1_0
×
45
        else:
46
            self.namespace = OWS_NAMESPACE_2_0_0
1✔
47

48

49
class ServiceIdentification(object):
1✔
50
    """Initialize an OWS Common ServiceIdentification construct"""
51
    def __init__(self, infoset, namespace=DEFAULT_OWS_NAMESPACE):
1✔
52
        self._root = infoset
1✔
53

54
        val = self._root.find(util.nspath('Title', namespace))
1✔
55
        self.title = util.testXMLValue(val)
1✔
56

57
        val = self._root.find(util.nspath('Abstract', namespace))
1✔
58
        self.abstract = util.testXMLValue(val)
1✔
59

60
        self.keywords = []
1✔
61
        for f in self._root.findall(util.nspath('Keywords/Keyword', namespace)):
1✔
62
            if f.text is not None:
1✔
63
                self.keywords.append(f.text)
1✔
64

65
        val = self._root.find(util.nspath('Keywords/Type', namespace))
1✔
66
        self.keywords_type = util.testXMLValue(val)
1✔
67

68
        val = self._root.find(util.nspath('AccessConstraints', namespace))
1✔
69
        self.accessconstraints = util.testXMLValue(val)
1✔
70

71
        val = self._root.find(util.nspath('Fees', namespace))
1✔
72
        self.fees = util.testXMLValue(val)
1✔
73

74
        val = self._root.find(util.nspath('ServiceType', namespace))
1✔
75
        self.type = util.testXMLValue(val)
1✔
76
        self.service = self.type  # alternative? keep both?discuss
1✔
77

78
        val = self._root.find(util.nspath('ServiceTypeVersion', namespace))
1✔
79
        self.version = util.testXMLValue(val)
1✔
80

81
        self.versions = []
1✔
82
        for v in self._root.findall(util.nspath('ServiceTypeVersion', namespace)):
1✔
83
            self.versions.append(util.testXMLValue(v))
1✔
84

85
        self.profiles = []
1✔
86
        for p in self._root.findall(util.nspath('Profile', namespace)):
1✔
87
            self.profiles.append(util.testXMLValue(p))
1✔
88

89
    def __str__(self):
1✔
90
        return 'Service: {}, title={}'.format(self.service, self.title or '')
×
91

92
    def __repr__(self):
1✔
93
        return '<owslib.ows.ServiceIdentification {} at {}>'.format(self.service, hex(id(self)))
×
94

95

96
class ServiceProvider(object):
1✔
97
    """Initialize an OWS Common ServiceProvider construct"""
98
    def __init__(self, infoset, namespace=DEFAULT_OWS_NAMESPACE):
1✔
99
        self._root = infoset
1✔
100
        val = self._root.find(util.nspath('ProviderName', namespace))
1✔
101
        self.name = util.testXMLValue(val)
1✔
102
        self.contact = ServiceContact(infoset, namespace)
1✔
103
        val = self._root.find(util.nspath('ProviderSite', namespace))
1✔
104
        if val is not None:
1✔
105
            try:
1✔
106
                urlattrib = val.attrib[util.nspath('href', XLINK_NAMESPACE)]
1✔
107
                self.url = util.testXMLValue(urlattrib, True)
1✔
108
            except KeyError:
×
109
                self.url = None
×
110
        else:
111
            self.url = None
1✔
112

113

114
class ServiceContact(object):
1✔
115
    """Initialize an OWS Common ServiceContact construct"""
116
    def __init__(self, infoset, namespace=DEFAULT_OWS_NAMESPACE):
1✔
117
        self._root = infoset
1✔
118
        val = self._root.find(util.nspath('ProviderName', namespace))
1✔
119
        self.name = util.testXMLValue(val)
1✔
120
        self.organization = util.testXMLValue(
1✔
121
            self._root.find(util.nspath('ContactPersonPrimary/ContactOrganization', namespace)))
122

123
        val = self._root.find(util.nspath('ProviderSite', namespace))
1✔
124
        if val is not None:
1✔
125
            self.site = util.testXMLValue(val.attrib.get(util.nspath('href', XLINK_NAMESPACE)), True)
1✔
126
        else:
127
            self.site = None
1✔
128

129
        val = self._root.find(util.nspath('ServiceContact/Role', namespace))
1✔
130
        self.role = util.testXMLValue(val)
1✔
131

132
        val = self._root.find(util.nspath('ServiceContact/IndividualName', namespace))
1✔
133
        self.name = util.testXMLValue(val)
1✔
134

135
        val = self._root.find(util.nspath('ServiceContact/PositionName', namespace))
1✔
136
        self.position = util.testXMLValue(val)
1✔
137

138
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/Phone/Voice', namespace))
1✔
139
        self.phone = util.testXMLValue(val)
1✔
140

141
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/Phone/Facsimile', namespace))
1✔
142
        self.fax = util.testXMLValue(val)
1✔
143

144
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/Address/DeliveryPoint', namespace))
1✔
145
        self.address = util.testXMLValue(val)
1✔
146

147
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/Address/City', namespace))
1✔
148
        self.city = util.testXMLValue(val)
1✔
149

150
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/Address/AdministrativeArea', namespace))
1✔
151
        self.region = util.testXMLValue(val)
1✔
152

153
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/Address/PostalCode', namespace))
1✔
154
        self.postcode = util.testXMLValue(val)
1✔
155

156
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/Address/Country', namespace))
1✔
157
        self.country = util.testXMLValue(val)
1✔
158

159
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/Address/ElectronicMailAddress', namespace))
1✔
160
        self.email = util.testXMLValue(val)
1✔
161

162
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/OnlineResource', namespace))
1✔
163
        if val is not None:
1✔
164
            self.url = util.testXMLValue(val.attrib.get(util.nspath('href', XLINK_NAMESPACE)), True)
1✔
165
        else:
166
            self.url = None
1✔
167

168
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/HoursOfService', namespace))
1✔
169
        self.hours = util.testXMLValue(val)
1✔
170

171
        val = self._root.find(util.nspath('ServiceContact/ContactInfo/ContactInstructions', namespace))
1✔
172
        self.instructions = util.testXMLValue(val)
1✔
173

174

175
class Constraint(object):
1✔
176
    def __init__(self, elem, namespace=DEFAULT_OWS_NAMESPACE):
1✔
177
        self.name = elem.attrib.get('name')
1✔
178
        self.values = [i.text for i in elem.findall(util.nspath('Value', namespace))]
1✔
179
        self.values += [i.text for i in elem.findall(util.nspath('AllowedValues/Value', namespace))]
1✔
180

181
    def __repr__(self):
1✔
182
        if self.values:
×
183
            return "Constraint: %s - %s" % (self.name, self.values)
×
184
        else:
185
            return "Constraint: %s" % self.name
×
186

187

188
class Parameter(object):
1✔
189
    def __init__(self, elem, namespace=DEFAULT_OWS_NAMESPACE):
1✔
190
        self.name = elem.attrib.get('name')
1✔
191
        self.values = [i.text for i in elem.findall(util.nspath('Value', namespace))]
1✔
192
        self.values += [i.text for i in elem.findall(util.nspath('AllowedValues/Value', namespace))]
1✔
193

194
    def __repr__(self):
1✔
195
        if self.values:
×
196
            return "Parameter: %s - %s" % (self.name, self.values)
×
197
        else:
198
            return "Parameter: %s" % self.name
×
199

200

201
class OperationsMetadata(object):
1✔
202
    """Initialize an OWS OperationMetadata construct"""
203
    def __init__(self, elem, namespace=DEFAULT_OWS_NAMESPACE):
1✔
204
        if 'name' not in elem.attrib:  # This is not a valid element
1✔
205
            return
1✔
206
        self.name = elem.attrib['name']
1✔
207
        self.formatOptions = ['text/xml']
1✔
208
        parameters = []
1✔
209
        self.methods = []
1✔
210
        self.constraints = []
1✔
211

212
        for verb in elem.findall(util.nspath('DCP/HTTP/*', namespace)):
1✔
213
            url = util.testXMLAttribute(verb, util.nspath('href', XLINK_NAMESPACE))
1✔
214
            if url is not None:
1✔
215
                verb_constraints = [Constraint(conts, namespace) for conts in verb.findall(
1✔
216
                    util.nspath('Constraint', namespace))]
217
                self.methods.append({'constraints': verb_constraints, 'type': util.xmltag_split(verb.tag), 'url': url})
1✔
218

219
        for parameter in elem.findall(util.nspath('Parameter', namespace)):
1✔
220
            if namespace == OWS_NAMESPACE_1_1_0:
1✔
221
                parameters.append((parameter.attrib['name'], {'values': [i.text for i in parameter.findall(
1✔
222
                    util.nspath('AllowedValues/Value', namespace))]}))
223
            else:
224
                parameters.append((parameter.attrib['name'], {'values': [i.text for i in parameter.findall(
1✔
225
                    util.nspath('Value', namespace))]}))
226
        self.parameters = dict(parameters)
1✔
227

228
        for constraint in elem.findall(util.nspath('Constraint', namespace)):
1✔
229
            self.constraints.append(Constraint(constraint, namespace))
1✔
230

231
    def __str__(self):
1✔
232
        return "Operation: {}, format={}".format(self.name, self.formatOptions)
×
233

234
    def __repr__(self):
1✔
235
        return '<owslib.ows.OperationsMetadata {} at {}>'.format(self.name, hex(id(self)))
×
236

237

238
class BoundingBox(object):
1✔
239
    """Initialize an OWS BoundingBox construct"""
240
    def __init__(self, elem, namespace=DEFAULT_OWS_NAMESPACE):
1✔
241
        self.minx = None
1✔
242
        self.miny = None
1✔
243
        self.maxx = None
1✔
244
        self.maxy = None
1✔
245
        self.crs = None
1✔
246
        self.dimensions = 2
1✔
247
        if elem is None:
1✔
248
            return
×
249
        val = elem.attrib.get('crs') or elem.attrib.get('{{{}}}crs'.format(namespace))
1✔
250
        if val:
1✔
251
            try:
1✔
252
                self.crs = crs.Crs(val)
1✔
253
            except (AttributeError, ValueError):
×
254
                LOGGER.warning('Invalid CRS %r. Expected integer' % val)
×
255
        else:
256
            self.crs = None
1✔
257

258
        val = elem.attrib.get('dimensions') or elem.attrib.get('{{{}}}dimensions'.format(namespace))
1✔
259
        if val is not None:
1✔
260
            self.dimensions = int(util.testXMLValue(val, True))
1✔
261
        else:  # assume 2
262
            self.dimensions = 2
1✔
263

264
        val = elem.find(util.nspath('LowerCorner', namespace))
1✔
265
        tmp = util.testXMLValue(val)
1✔
266
        if tmp is not None:
1✔
267
            xy = tmp.split()
1✔
268
            if len(xy) > 1:
1✔
269
                if self.crs is not None and self.crs.axisorder == 'yx':
1✔
270
                    self.minx, self.miny = xy[1], xy[0]
1✔
271
                else:
272
                    self.minx, self.miny = xy[0], xy[1]
1✔
273

274
        val = elem.find(util.nspath('UpperCorner', namespace))
1✔
275
        tmp = util.testXMLValue(val)
1✔
276
        if tmp is not None:
1✔
277
            xy = tmp.split()
1✔
278
            if len(xy) > 1:
1✔
279
                if self.crs is not None and self.crs.axisorder == 'yx':
1✔
280
                    self.maxx, self.maxy = xy[1], xy[0]
1✔
281
                else:
282
                    self.maxx, self.maxy = xy[0], xy[1]
1✔
283

284

285
class WGS84BoundingBox(BoundingBox):
1✔
286
    """WGS84 bbox, axis order xy"""
287
    def __init__(self, elem, namespace=DEFAULT_OWS_NAMESPACE):
1✔
288
        BoundingBox.__init__(self, elem, namespace)
×
289
        self.dimensions = 2
×
290
        self.crs = crs.Crs('urn:ogc:def:crs:OGC:2:84')
×
291

292

293
class ExceptionReport(Exception):
1✔
294
    """OWS ExceptionReport"""
295

296
    def __init__(self, elem, namespace=DEFAULT_OWS_NAMESPACE):
1✔
297
        self.exceptions = []
×
298

299
        if hasattr(elem, 'getroot'):
×
300
            elem = elem.getroot()
×
301

302
        for i in elem.findall(util.nspath('Exception', namespace)):
×
303
            tmp = {}
×
304
            val = i.attrib.get('exceptionCode')
×
305
            tmp['exceptionCode'] = util.testXMLValue(val, True)
×
306
            val = i.attrib.get('locator')
×
307
            tmp['locator'] = util.testXMLValue(val, True)
×
308
            val = i.find(util.nspath('ExceptionText', namespace))
×
309
            tmp['ExceptionText'] = util.testXMLValue(val)
×
310
            self.exceptions.append(tmp)
×
311

312
        # set topmost stacktrace as return message
313
        self.code = self.exceptions[0]['exceptionCode']
×
314
        self.locator = self.exceptions[0]['locator']
×
315
        self.msg = self.exceptions[0]['ExceptionText']
×
316
        self.xml = etree.tostring(elem)
×
317

318
    def __str__(self):
1✔
319
        return repr(self.msg)
×
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