def openURL(url_base, data, method='Get', cookies=None, username=None, password=None, timeout=30): ''' function to open urls - wrapper around urllib2.urlopen but with additional checks for OGC service exceptions and url formatting, also handles cookies and simple user password authentication''' url_base.strip() lastchar = url_base[-1] if lastchar not in ['?', '&']: if url_base.find('?') == -1: url_base = url_base + '?' else: url_base = url_base + '&' if username and password: # Provide login information in order to use the WMS server # Create an OpenerDirector with support for Basic HTTP # Authentication... passman = HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, url_base, username, password) auth_handler = HTTPBasicAuthHandler(passman) opener = urllib2.build_opener(auth_handler) openit = opener.open else: # NOTE: optionally set debuglevel>0 to debug HTTP connection #opener = urllib2.build_opener(urllib2.HTTPHandler(debuglevel=0)) #openit = opener.open openit = urlopen try: if method == 'Post': req = Request(url_base, data) # set appropriate header if posting XML try: xml = etree.fromstring(data) req.add_header('Content-Type', "text/xml") except: pass else: req=Request(url_base + data) if cookies is not None: req.add_header('Cookie', cookies) u = openit(req, timeout=timeout) except HTTPError as e: #Some servers may set the http header to 400 if returning an OGC service exception or 401 if unauthorised. if e.code in [400, 401]: raise ServiceException(e.read()) else: raise e # check for service exceptions without the http header set if 'Content-Type' in u.info() and u.info()['Content-Type'] in ['text/xml', 'application/xml']: #just in case 400 headers were not set, going to have to read the xml to see if it's an exception report. #wrap the url stram in a extended StringIO object so it's re-readable u=RereadableURL(u) se_xml= u.read() se_tree = etree.fromstring(se_xml) serviceException=se_tree.find('{http://www.opengis.net/ows}Exception') if serviceException is None: serviceException=se_tree.find('ServiceException') if serviceException is not None: raise ServiceException(str(serviceException.text).strip()) u.seek(0) #return cursor to start of u return u
def _getStoredQueries(self): ''' gets descriptions of the stored queries available on the server ''' sqs=[] #This method makes two calls to the WFS - one ListStoredQueries, and one DescribeStoredQueries. The information is then #aggregated in 'StoredQuery' objects method=nspath('Get') #first make the ListStoredQueries response and save the results in a dictionary if form {storedqueryid:(title, returnfeaturetype)} try: base_url = next((m.get('url') for m in self.getOperationByName('ListStoredQueries').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = {'service': 'WFS', 'version': self.version, 'request': 'ListStoredQueries'} encoded_request = urlencode(request) u = urlopen(base_url, data=encoded_request, timeout=self.timeout) tree=etree.fromstring(u.read()) tempdict={} for sqelem in tree[:]: title=rft=id=None id=sqelem.get('id') for elem in sqelem[:]: if elem.tag==nspath('Title', WFS_NAMESPACE): title=elem.text elif elem.tag==nspath('ReturnFeatureType', WFS_NAMESPACE): rft=elem.text tempdict[id]=(title,rft) #store in temporary dictionary #then make the DescribeStoredQueries request and get the rest of the information about the stored queries try: base_url = next((m.get('url') for m in self.getOperationByName('DescribeStoredQueries').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = {'service': 'WFS', 'version': self.version, 'request': 'DescribeStoredQueries'} encoded_request = urlencode(request) u = urlopen(base_url, data=encoded_request, timeout=to) tree=etree.fromstring(u.read()) tempdict2={} for sqelem in tree[:]: params=[] #list to store parameters for the stored query description id =sqelem.get('id') for elem in sqelem[:]: if elem.tag==nspath('Abstract', WFS_NAMESPACE): abstract=elem.text elif elem.tag==nspath('Parameter', WFS_NAMESPACE): newparam=Parameter(elem.get('name'), elem.get('type')) params.append(newparam) tempdict2[id]=(abstract, params) #store in another temporary dictionary #now group the results into StoredQuery objects: for key in tempdict.keys(): abstract='blah' parameters=[] sqs.append(StoredQuery(key, tempdict[key][0], tempdict[key][1], tempdict2[key][0], tempdict2[key][1])) return sqs
def cleanup_namespaces(element): """ Remove unused namespaces from an element """ if etree.__name__ == 'lxml.etree': etree.cleanup_namespaces(element) return element else: return etree.fromstring(etree.tostring(element))
def cleanup_namespaces(element): """ Remove unused namespaces from an element """ if etree.__name__ == 'lxml.etree': etree.cleanup_namespaces(element) return element else: return etree.fromstring(etree.tostring(element))
def readString(self, st): """Parse a WMS capabilities document, returning an elementtree instance string should be an XML capabilities document """ if not isinstance(st, str): raise ValueError("String must be of type string, not %s" % type(st)) return etree.fromstring(st)
def get_observation(self, responseFormat=None, offerings=None, observedProperties=None, eventTime=None, method='Get', **kwargs): """ Parameters ---------- format : string Output format. Provide one that is available for all offerings method : string Optional. HTTP DCP method name: Get or Post. Must **kwargs : extra arguments anything else e.g. vendor specific parameters """ base_url = self.get_operation_by_name('GetObservation').methods[method]['url'] request = {'service': 'SOS', 'version': self.version, 'request': 'GetObservation'} # Required Fields assert isinstance(offerings, list) and len(offerings) > 0 request['offering'] = ','.join(offerings) assert isinstance(observedProperties, list) and len(observedProperties) > 0 request['observedProperty'] = ','.join(observedProperties) if responseFormat is not None: request['responseFormat'] = responseFormat # Optional Fields if eventTime is not None: request['temporalFilter'] = eventTime url_kwargs = {} if 'timeout' in kwargs: url_kwargs['timeout'] = kwargs.pop('timeout') # Client specified timeout value if kwargs: for kw in kwargs: request[kw] = kwargs[kw] data = urlencode(request) response = openURL( base_url, data, method, username=self.username, password=self.password, **url_kwargs ).read() try: tr = etree.fromstring(response) if tr.tag == nspath_eval("ows:ExceptionReport", namespaces): raise ows.ExceptionReport(tr) else: return response except ows.ExceptionReport: raise except BaseException: return response
def readString(self, st): """Parse a WCS capabilities document, returning an instance of WCSCapabilitiesInfoset string should be an XML capabilities document """ if not isinstance(st, str): raise ValueError("String must be of type string, not %s" % type(st)) return etree.fromstring(st)
def __init__(self, element): if isinstance(element, str): self._root = etree.fromstring(element) else: self._root = element if hasattr(self._root, 'getroot'): self._root = self._root.getroot() self.members = [Member(x) for x in self._root.findall(nsp('sml:member'))]
def read_string(self, st): """ Parse a SOS capabilities document, returning an elementtree instance st should be an XML capabilities document """ if not isinstance(st, str): raise ValueError("String must be of type string, not %s" % type(st)) return etree.fromstring(st)
def __init__(self, element): if isinstance(element, str) or isinstance(element, unicode): self._root = etree.fromstring(str(element)) else: self._root = element if hasattr(self._root, 'getroot'): self._root = self._root.getroot() self._ns = 'wml1.1'
def __init__(self, element): if isinstance(element, str) or isinstance(element, unicode): self._root = etree.fromstring(str(element)) else: self._root = element if hasattr(self._root, 'getroot'): self._root = self._root.getroot() self._ns = 'wml1.0'
def __init__(self, element): if isinstance(element, str): self._root = etree.fromstring(element) else: self._root = element if hasattr(self._root, 'getroot'): self._root = self._root.getroot() self.members = [ Member(x) for x in self._root.findall(nsp('sml:member')) ]
def read(self, service_url): """ Get and parse a WMS capabilities document, returning an elementtree instance service_url is the base url, to which is appended the service, version, and request parameters """ getcaprequest = self.capabilities_url(service_url) spliturl=getcaprequest.split('?') u = openURL(spliturl[0], spliturl[1], method='Get', username=self.username, password=self.password) return etree.fromstring(u.read())
def describe_sensor(self, outputFormat=None, procedure=None, method='Get', **kwargs): try: base_url = next( (m.get('url') for m in self.getOperationByName('DescribeSensor').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = { 'service': 'SOS', 'version': self.version, 'request': 'DescribeSensor' } # Required Fields assert isinstance(outputFormat, str) request['outputFormat'] = outputFormat assert isinstance(procedure, str) request['procedure'] = procedure url_kwargs = {} if 'timeout' in kwargs: url_kwargs['timeout'] = kwargs.pop( 'timeout') # Client specified timeout value # Optional Fields if kwargs: for kw in kwargs: request[kw] = kwargs[kw] data = urlencode(request) response = openURL(base_url, data, method, username=self.username, password=self.password, **url_kwargs).read() tr = etree.fromstring(response) if tr.tag == nspath_eval("ows:ExceptionReport", namespaces): raise ows.ExceptionReport(tr) return response
def read(self, url, timeout=30): """Get and parse a WFS capabilities document, returning an instance of WFSCapabilitiesInfoset Parameters ---------- url : string The URL to the WFS capabilities document. timeout : number A timeout value (in seconds) for the request. """ request = self.capabilities_url(url) u = urlopen(request, timeout=timeout) return etree.fromstring(u.read())
def read(self, url, timeout=30): """Get and parse a WFS capabilities document, returning an instance of WFSCapabilitiesInfoset Parameters ---------- url : string The URL to the WFS capabilities document. timeout : number A timeout value (in seconds) for the request. """ request = self.capabilities_url(url) u = urlopen(request, timeout=timeout) return etree.fromstring(u.read())
def read(self, service_url, timeout=30): """Get and parse a WCS capabilities document, returning an elementtree tree @type service_url: string @param service_url: The base url, to which is appended the service, version, and request parameters @rtype: elementtree tree @return: An elementtree tree representation of the capabilities document """ request = self.capabilities_url(service_url) req = Request(request) if self.cookies is not None: req.add_header('Cookie', self.cookies) u = urlopen(req, timeout=timeout) return etree.fromstring(u.read())
def read(self, service_url): """ Get and parse a WMS capabilities document, returning an elementtree instance service_url is the base url, to which is appended the service, acceptVersions, and request parameters """ getcaprequest = self.capabilities_url(service_url) spliturl = getcaprequest.split('?') u = openURL(spliturl[0], spliturl[1], method='Get', username=self.username, password=self.password) return etree.fromstring(u.read())
def getcapabilities(self): """Request and return capabilities document from the WMS as a file-like object. NOTE: this is effectively redundant now""" reader = WMSCapabilitiesReader( self.version, url=self.url, un=self.username, pw=self.password ) u = self._open(reader.capabilities_url(self.url)) # check for service exceptions, and return if u.info().gettype() == 'application/vnd.ogc.se_xml': se_xml = u.read() se_tree = etree.fromstring(se_xml) err_message = str(se_tree.find('ServiceException').text).strip() raise ServiceException(err_message, se_xml) return u
def read(self, service_url, timeout=30): """Get and parse a WCS capabilities document, returning an elementtree tree @type service_url: string @param service_url: The base url, to which is appended the service, version, and request parameters @rtype: elementtree tree @return: An elementtree tree representation of the capabilities document """ request = self.capabilities_url(service_url) req = Request(request) if self.cookies is not None: req.add_header('Cookie', self.cookies) u = urlopen(req, timeout=timeout) return etree.fromstring(u.read())
def describe_sensor(self, outputFormat=None, procedure=None, method='Get', **kwargs): try: base_url = next(( m.get('url') for m in self.getOperationByName('DescribeSensor').methods if m.get('type').lower() == method.lower()) ) except StopIteration: base_url = self.url request = {'service': 'SOS', 'version': self.version, 'request': 'DescribeSensor'} # Required Fields assert isinstance(outputFormat, str) request['outputFormat'] = outputFormat assert isinstance(procedure, str) request['procedure'] = procedure url_kwargs = {} if 'timeout' in kwargs: url_kwargs['timeout'] = kwargs.pop('timeout') # Client specified timeout value # Optional Fields if kwargs: for kw in kwargs: request[kw] = kwargs[kw] data = urlencode(request) response = openURL( base_url, data, method, username=self.username, password=self.password, **url_kwargs ).read() tr = etree.fromstring(response) if tr.tag == nspath_eval("ows:ExceptionReport", namespaces): raise ows.ExceptionReport(tr) return response
def getcapabilities(self): """Request and return capabilities document from the WMS as a file-like object. NOTE: this is effectively redundant now""" reader = WMSCapabilitiesReader(self.version, url=self.url, un=self.username, pw=self.password) u = self._open(reader.capabilities_url(self.url)) # check for service exceptions, and return if u.info().gettype() == 'application/vnd.ogc.se_xml': se_xml = u.read() se_tree = etree.fromstring(se_xml) err_message = str(se_tree.find('ServiceException').text).strip() raise ServiceException(err_message, se_xml) return u
def getCoverages(self, unpackdir='./unpacked'): if self.urlType=='XML': paths=[] u_xml = self.u.read() u_tree = etree.fromstring(u_xml) for ref in u_tree.findall('{http://www.opengis.net/wcs/1.1}Coverage/{http://www.opengis.net/wcs/1.1}Reference'): path = ref.attrib['{http://www.w3.org/1999/xlink}href'] paths.append(path) for ref in u_tree.findall('{http://www.opengis.net/wcs/1.1.0/owcs}Coverage/{{http://www.opengis.net/wcs/1.1.0/owcs}Reference'): path = ref.attrib['{http://www.w3.org/1999/xlink}href'] paths.append(path) elif self.urlType=='Multipart': #Decode multipart mime and return fileobjects u_mpart=self.u.read() mpart =MpartMime(u_mpart) paths= mpart.unpackToDir(unpackdir) return paths
def getCoverages(self, unpackdir='./unpacked'): if self.urlType == 'XML': paths = [] u_xml = self.u.read() u_tree = etree.fromstring(u_xml) for ref in u_tree.findall( '{http://www.opengis.net/wcs/1.1}Coverage/{http://www.opengis.net/wcs/1.1}Reference' ): path = ref.attrib['{http://www.w3.org/1999/xlink}href'] paths.append(path) for ref in u_tree.findall( '{http://www.opengis.net/wcs/1.1.0/owcs}Coverage/{{http://www.opengis.net/wcs/1.1.0/owcs}Reference' ): path = ref.attrib['{http://www.w3.org/1999/xlink}href'] paths.append(path) elif self.urlType == 'Multipart': #Decode multipart mime and return fileobjects u_mpart = self.u.read() mpart = MpartMime(u_mpart) paths = mpart.unpackToDir(unpackdir) return paths
def getmap(self, layers=None, styles=None, srs=None, bbox=None, format=None, size=None, time=None, transparent=False, bgcolor='#FFFFFF', exceptions='application/vnd.ogc.se_xml', method='Get', **kwargs ): """Request and return an image from the WMS as a file-like object. Parameters ---------- layers : list List of content layer names. styles : list Optional list of named styles, must be the same length as the layers list. srs : string A spatial reference system identifier. bbox : tuple (left, bottom, right, top) in srs units. format : string Output image format such as 'image/jpeg'. size : tuple (width, height) in pixels. transparent : bool Optional. Transparent background if True. bgcolor : string Optional. Image background color. method : string Optional. HTTP DCP method name: Get or Post. **kwargs : extra arguments anything else e.g. vendor specific parameters Example ------- >>> wms = WebMapService('http://giswebservices.massgis.state.ma.us/geoserver/wms', version='1.1.1') >>> img = wms.getmap(layers=['massgis:GISDATA.SHORELINES_ARC'],\ styles=[''],\ srs='EPSG:4326',\ bbox=(-70.8, 42, -70, 42.8),\ size=(300, 300),\ format='image/jpeg',\ transparent=True) >>> out = open('example.jpg.jpg', 'wb') >>> out.write(img.read()) >>> out.close() """ try: base_url = next((m.get('url') for m in self.getOperationByName('GetMap').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = {'version': self.version, 'request': 'GetMap'} # check layers and styles assert len(layers) > 0 request['layers'] = ','.join(layers) if styles: assert len(styles) == len(layers) request['styles'] = ','.join(styles) else: request['styles'] = '' # size request['width'] = str(size[0]) request['height'] = str(size[1]) request['srs'] = str(srs) request['bbox'] = ','.join([repr(x) for x in bbox]) request['format'] = str(format) request['transparent'] = str(transparent).upper() request['bgcolor'] = '0x' + bgcolor[1:7] request['exceptions'] = str(exceptions) if time is not None: request['time'] = str(time) if kwargs: for kw in kwargs: request[kw]=kwargs[kw] data = urlencode(request) u = openURL(base_url, data, method, username = self.username, password = self.password) # check for service exceptions, and return if u.info()['Content-Type'] == 'application/vnd.ogc.se_xml': se_xml = u.read() se_tree = etree.fromstring(se_xml) err_message = unicode(se_tree.find('ServiceException').text).strip() raise ServiceException(err_message, se_xml) return u
def get_observation(self, responseFormat=None, offerings=None, observedProperties=None, eventTime=None, method='Get', **kwargs): """ Parameters ---------- format : string Output format. Provide one that is available for all offerings method : string Optional. HTTP DCP method name: Get or Post. Must **kwargs : extra arguments anything else e.g. vendor specific parameters """ try: base_url = next( (m.get('url') for m in self.getOperationByName('GetObservation').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = { 'service': 'SOS', 'version': self.version, 'request': 'GetObservation' } # Required Fields assert isinstance(offerings, list) and len(offerings) > 0 request['offering'] = ','.join(offerings) assert isinstance(observedProperties, list) and len(observedProperties) > 0 request['observedProperty'] = ','.join(observedProperties) assert isinstance(responseFormat, str) request['responseFormat'] = responseFormat # Optional Fields if eventTime is not None: request['eventTime'] = eventTime url_kwargs = {} if 'timeout' in kwargs: url_kwargs['timeout'] = kwargs.pop( 'timeout') # Client specified timeout value if kwargs: for kw in kwargs: request[kw] = kwargs[kw] data = urlencode(request) response = openURL(base_url, data, method, username=self.username, password=self.password, **url_kwargs).read() try: tr = etree.fromstring(response) if tr.tag == nspath_eval("ows:ExceptionReport", namespaces): raise ows.ExceptionReport(tr) else: return response except ows.ExceptionReport: raise except BaseException: return response
def openURL(url_base, data, method='Get', cookies=None, username=None, password=None, timeout=30): ''' function to open urls - wrapper around urllib2.urlopen but with additional checks for OGC service exceptions and url formatting, also handles cookies and simple user password authentication''' url_base.strip() lastchar = url_base[-1] if lastchar not in ['?', '&']: if url_base.find('?') == -1: url_base = url_base + '?' else: url_base = url_base + '&' if username and password: # Provide login information in order to use the WMS server # Create an OpenerDirector with support for Basic HTTP # Authentication... passman = HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, url_base, username, password) auth_handler = HTTPBasicAuthHandler(passman) opener = urllib2.build_opener(auth_handler) openit = opener.open else: # NOTE: optionally set debuglevel>0 to debug HTTP connection #opener = urllib2.build_opener(urllib2.HTTPHandler(debuglevel=0)) #openit = opener.open openit = urlopen try: if method == 'Post': req = Request(url_base, data) # set appropriate header if posting XML try: xml = etree.fromstring(data) req.add_header('Content-Type', "text/xml") except: pass else: req = Request(url_base + data) if cookies is not None: req.add_header('Cookie', cookies) u = openit(req, timeout=timeout) except HTTPError as e: #Some servers may set the http header to 400 if returning an OGC service exception or 401 if unauthorised. if e.code in [400, 401]: raise ServiceException(e.read()) else: raise e # check for service exceptions without the http header set if 'Content-Type' in u.info() and u.info()['Content-Type'] in [ 'text/xml', 'application/xml' ]: #just in case 400 headers were not set, going to have to read the xml to see if it's an exception report. #wrap the url stram in a extended StringIO object so it's re-readable u = RereadableURL(u) se_xml = u.read() se_tree = etree.fromstring(se_xml) serviceException = se_tree.find( '{http://www.opengis.net/ows}Exception') if serviceException is None: serviceException = se_tree.find('ServiceException') if serviceException is not None: raise ServiceException(str(serviceException.text).strip()) u.seek(0) #return cursor to start of u return u
def getmap(self, layers=None, styles=None, srs=None, bbox=None, format=None, size=None, time=None, transparent=False, bgcolor='#FFFFFF', exceptions='application/vnd.ogc.se_xml', method='Get', **kwargs): """Request and return an image from the WMS as a file-like object. Parameters ---------- layers : list List of content layer names. styles : list Optional list of named styles, must be the same length as the layers list. srs : string A spatial reference system identifier. bbox : tuple (left, bottom, right, top) in srs units. format : string Output image format such as 'image/jpeg'. size : tuple (width, height) in pixels. transparent : bool Optional. Transparent background if True. bgcolor : string Optional. Image background color. method : string Optional. HTTP DCP method name: Get or Post. **kwargs : extra arguments anything else e.g. vendor specific parameters Example ------- >>> wms = WebMapService('http://giswebservices.massgis.state.ma.us/geoserver/wms', version='1.1.1') >>> img = wms.getmap(layers=['massgis:GISDATA.SHORELINES_ARC'],\ styles=[''],\ srs='EPSG:4326',\ bbox=(-70.8, 42, -70, 42.8),\ size=(300, 300),\ format='image/jpeg',\ transparent=True) >>> out = open('example.jpg.jpg', 'wb') >>> out.write(img.read()) >>> out.close() """ try: base_url = next((m.get('url') for m in self.getOperationByName('GetMap').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = {'version': self.version, 'request': 'GetMap'} # check layers and styles assert len(layers) > 0 request['layers'] = ','.join(layers) if styles: assert len(styles) == len(layers) request['styles'] = ','.join(styles) else: request['styles'] = '' # size request['width'] = str(size[0]) request['height'] = str(size[1]) request['srs'] = str(srs) request['bbox'] = ','.join([repr(x) for x in bbox]) request['format'] = str(format) request['transparent'] = str(transparent).upper() request['bgcolor'] = '0x' + bgcolor[1:7] request['exceptions'] = str(exceptions) if time is not None: request['time'] = str(time) if kwargs: for kw in kwargs: request[kw] = kwargs[kw] data = urlencode(request) u = openURL(base_url, data, method, username=self.username, password=self.password) # check for service exceptions, and return if u.info()['Content-Type'] == 'application/vnd.ogc.se_xml': se_xml = u.read() se_tree = etree.fromstring(se_xml) err_message = unicode( se_tree.find('ServiceException').text).strip() raise ServiceException(err_message, se_xml) return u
def getfeature(self, typename=None, filter=None, bbox=None, featureid=None, featureversion=None, propertyname=['*'], maxfeatures=None, srsname=None, outputFormat=None, method='{http://www.opengis.net/wfs}Get', startindex=None): """Request and return feature data as a file-like object. Parameters ---------- typename : list List of typenames (string) filter : string XML-encoded OGC filter expression. bbox : tuple (left, bottom, right, top) in the feature type's coordinates. featureid : list List of unique feature ids (string) featureversion : string Default is most recent feature version. propertyname : list List of feature property names. '*' matches all. maxfeatures : int Maximum number of features to be returned. method : string Qualified name of the HTTP DCP method to use. srsname: string EPSG code to request the data in outputFormat: string (optional) Requested response format of the request. startindex: int (optional) Start position to return feature set (paging in combination with maxfeatures) There are 3 different modes of use 1) typename and bbox (simple spatial query) 2) typename and filter (more expressive) 3) featureid (direct access to known features) """ try: base_url = next( (m.get('url') for m in self.getOperationByName('GetFeature').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = { 'service': 'WFS', 'version': self.version, 'request': 'GetFeature' } # check featureid if featureid: request['featureid'] = ','.join(featureid) elif bbox and typename: request['bbox'] = ','.join([repr(x) for x in bbox]) elif filter and typename: request['filter'] = str(filter) if srsname: request['srsname'] = str(srsname) assert len(typename) > 0 request['typename'] = ','.join(typename) if propertyname: request['propertyname'] = ','.join(propertyname) if featureversion: request['featureversion'] = str(featureversion) if maxfeatures: request['maxfeatures'] = str(maxfeatures) if startindex: request['startindex'] = str(startindex) if outputFormat is not None: request["outputFormat"] = outputFormat data = urlencode(request) log.debug("Making request: %s?%s" % (base_url, data)) u = openURL(base_url, data, method, timeout=self.timeout) # check for service exceptions, rewrap, and return # We're going to assume that anything with a content-length > 32k # is data. We'll check anything smaller. try: length = int(u.info()['Content-Length']) have_read = False except (KeyError, AttributeError): data = u.read() have_read = True length = len(data) if length < 32000: if not have_read: data = u.read() try: tree = etree.fromstring(data) except BaseException: # Not XML return StringIO(data) else: if tree.tag == "{%s}ServiceExceptionReport" % OGC_NAMESPACE: se = tree.find(nspath('ServiceException', OGC_NAMESPACE)) raise ServiceException(str(se.text).strip()) else: return StringIO(data) else: if have_read: return StringIO(data) return u
def getmap(self, layers=None, styles=None, srs=None, bbox=None, format=None, size=None, time=None, transparent=False, bgcolor='#FFFFFF', exceptions='XML', method='Get', **kwargs ): """Request and return an image from the WMS as a file-like object. Parameters ---------- layers : list List of content layer names. styles : list Optional list of named styles, must be the same length as the layers list. srs : string A spatial reference system identifier. bbox : tuple (left, bottom, right, top) in srs units. format : string Output image format such as 'image/jpeg'. size : tuple (width, height) in pixels. transparent : bool Optional. Transparent background if True. bgcolor : string Optional. Image background color. method : string Optional. HTTP DCP method name: Get or Post. **kwargs : extra arguments anything else e.g. vendor specific parameters Example ------- >>> wms = WebMapService('http://webservices.nationalatlas.gov/wms/1million', version='1.3.0') >>> img = wms.getmap(layers=['airports1m'],\ styles=['default'],\ srs='EPSG:4326',\ bbox=(-176.646, 17.7016, -64.8017, 71.2854),\ size=(300, 300),\ format='image/jpeg',\ transparent=True) >>> out = open('example.jpg.jpg', 'wb') >>> out.write(img.read()) >>> out.close() """ try: base_url = next((m.get('url') for m in self.getOperationByName('GetMap').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = {'version': self.version, 'request': 'GetMap'} # check layers and styles assert len(layers) > 0 request['layers'] = ','.join(layers) if styles: assert len(styles) == len(layers) request['styles'] = ','.join(styles) else: request['styles'] = '' # size request['width'] = str(size[0]) request['height'] = str(size[1]) request['crs'] = str(srs) request['bbox'] = ','.join([repr(x) for x in bbox]) request['format'] = str(format) request['transparent'] = str(transparent).upper() request['bgcolor'] = '0x' + bgcolor[1:7] request['exceptions'] = str(exceptions) if time is not None: request['time'] = str(time) if kwargs: for kw in kwargs: request[kw] = kwargs[kw] data = urlencode(request) print (data) u = openURL(base_url, data, method, username=self.username, password=self.password) # check for service exceptions, and return # error: AttributeError: 'RereadableURL' object has no attribute 'info' if u.info()['Content-Type'] in ['application/vnd.ogc.se_xml', 'text/xml']: se_xml = u.read() print (se_xml) se_tree = etree.fromstring(se_xml) # TODO: add the ogc namespace for this err_message = unicode(se_tree.find('{http://www.opengis.net/ogc}ServiceExceptionReport').text).strip() raise ServiceException(err_message, se_xml) return u
def getrecords2(self, constraints=[], sortby=None, typenames='csw:Record', esn='summary', outputschema=namespaces['csw'], format=outputformat, startposition=0, maxrecords=10, cql=None, xml=None, resulttype='results'): """ Construct and process a GetRecords request Parameters ---------- - constraints: the list of constraints (OgcExpression from owslib.fes module) - sortby: an OGC SortBy object (SortBy from owslib.fes module) - typenames: the typeNames to query against (default is csw:Record) - esn: the ElementSetName 'full', 'brief' or 'summary' (default is 'summary') - outputschema: the outputSchema (default is 'http://www.opengis.net/cat/csw/2.0.2') - format: the outputFormat (default is 'application/xml') - startposition: requests a slice of the result set, starting at this position (default is 0) - maxrecords: the maximum number of records to return. No records are returned if 0 (default is 10) - cql: common query language text. Note this overrides bbox, qtype, keywords - xml: raw XML request. Note this overrides all other options - resulttype: the resultType 'hits', 'results', 'validate' (default is 'results') """ if xml is not None: self.request = etree.fromstring(xml) val = self.request.find(util.nspath_eval('csw:Query/csw:ElementSetName', namespaces)) if val is not None: esn = util.testXMLValue(val) else: # construct request node0 = self._setrootelement('csw:GetRecords') if etree.__name__ != 'lxml.etree': # apply nsmap manually node0.set('xmlns:ows', namespaces['ows']) node0.set('xmlns:gmd', namespaces['gmd']) node0.set('xmlns:dif', namespaces['dif']) node0.set('xmlns:fgdc', namespaces['fgdc']) node0.set('outputSchema', outputschema) node0.set('outputFormat', format) node0.set('version', self.version) node0.set('service', self.service) node0.set('resultType', resulttype) if startposition > 0: node0.set('startPosition', str(startposition)) node0.set('maxRecords', str(maxrecords)) node0.set(util.nspath_eval('xsi:schemaLocation', namespaces), schema_location) node1 = etree.SubElement(node0, util.nspath_eval('csw:Query', namespaces)) node1.set('typeNames', typenames) etree.SubElement(node1, util.nspath_eval('csw:ElementSetName', namespaces)).text = esn if any([len(constraints) > 0, cql is not None]): node2 = etree.SubElement(node1, util.nspath_eval('csw:Constraint', namespaces)) node2.set('version', '1.1.0') flt = fes.FilterRequest() if len(constraints) > 0: node2.append(flt.setConstraintList(constraints)) # Now add a CQL filter if passed in elif cql is not None: etree.SubElement(node2, util.nspath_eval('csw:CqlText', namespaces)).text = cql if sortby is not None and isinstance(sortby, fes.SortBy): node1.append(sortby.toXML()) self.request = node0 self._invoke() if self.exceptionreport is None: self.results = {} # process search results attributes val = self._exml.find(util.nspath_eval('csw:SearchResults', namespaces)).attrib.get('numberOfRecordsMatched') self.results['matches'] = int(util.testXMLValue(val, True)) val = self._exml.find(util.nspath_eval('csw:SearchResults', namespaces)).attrib.get('numberOfRecordsReturned') self.results['returned'] = int(util.testXMLValue(val, True)) val = self._exml.find(util.nspath_eval('csw:SearchResults', namespaces)).attrib.get('nextRecord') if val is not None: self.results['nextrecord'] = int(util.testXMLValue(val, True)) else: warnings.warn("""CSW Server did not supply a nextRecord value (it is optional), so the client should page through the results in another way.""") # For more info, see: # https://github.com/geopython/OWSLib/issues/100 self.results['nextrecord'] = None # process list of matching records self.records = OrderedDict() self._parserecords(outputschema, esn)
def transaction(self, ttype=None, typename='csw:Record', record=None, propertyname=None, propertyvalue=None, bbox=None, keywords=[], cql=None, identifier=None): """ Construct and process a Transaction request Parameters ---------- - ttype: the type of transaction 'insert, 'update', 'delete' - typename: the typename to describe (default is 'csw:Record') - record: the XML record to insert - propertyname: the RecordProperty/PropertyName to Filter against - propertyvalue: the RecordProperty Value to Filter against (for updates) - bbox: the bounding box of the spatial query in the form [minx,miny,maxx,maxy] - keywords: list of keywords - cql: common query language text. Note this overrides bbox, qtype, keywords - identifier: record identifier. Note this overrides bbox, qtype, keywords, cql """ # construct request node0 = self._setrootelement('csw:Transaction') node0.set('version', self.version) node0.set('service', self.service) node0.set(util.nspath_eval('xsi:schemaLocation', namespaces), schema_location) validtransactions = ['insert', 'update', 'delete'] if ttype not in validtransactions: # invalid transaction raise RuntimeError('Invalid transaction \'%s\'.' % ttype) node1 = etree.SubElement(node0, util.nspath_eval('csw:%s' % ttype.capitalize(), namespaces)) if ttype != 'update': node1.set('typeName', typename) if ttype == 'insert': if record is None: raise RuntimeError('Nothing to insert.') node1.append(etree.fromstring(record)) if ttype == 'update': if record is not None: node1.append(etree.fromstring(record)) else: if propertyname is not None and propertyvalue is not None: node2 = etree.SubElement(node1, util.nspath_eval('csw:RecordProperty', namespaces)) etree.SubElement(node2, util.nspath_eval('csw:Name', namespaces)).text = propertyname etree.SubElement(node2, util.nspath_eval('csw:Value', namespaces)).text = propertyvalue self._setconstraint(node1, qtype, propertyname, keywords, bbox, cql, identifier) if ttype == 'delete': self._setconstraint(node1, None, propertyname, keywords, bbox, cql, identifier) self.request = node0 self._invoke() self.results = {} if self.exceptionreport is None: self._parsetransactionsummary() self._parseinsertresult()
def getfeature(self, typename=None, filter=None, bbox=None, featureid=None, featureversion=None, propertyname=['*'], maxfeatures=None, srsname=None, outputFormat=None, method='Get', startindex=None): """Request and return feature data as a file-like object. Parameters ---------- typename : list List of typenames (string) filter : string XML-encoded OGC filter expression. bbox : tuple (left, bottom, right, top) in the feature type's coordinates. featureid : list List of unique feature ids (string) featureversion : string Default is most recent feature version. propertyname : list List of feature property names. '*' matches all. maxfeatures : int Maximum number of features to be returned. method : string Qualified name of the HTTP DCP method to use. srsname: string EPSG code to request the data in outputFormat: string (optional) Requested response format of the request. startindex: int (optional) Start position to return feature set (paging in combination with maxfeatures) There are 3 different modes of use 1) typename and bbox (simple spatial query). It is assumed, that bbox coordinates are given *always* in the east,north order 2) typename and filter (more expressive) 3) featureid (direct access to known features) """ try: base_url = next( (m.get('url') for m in self.getOperationByName('GetFeature').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = { 'service': 'WFS', 'version': self.version, 'request': 'GetFeature' } if not isinstance(typename, list): typename = [typename] if srsname is not None: # check, if desired SRS is supported by the service for this typename if typename is not None: # convert srsname string to Crs object found in GetCaps srsnameobj = self.getSRS(srsname, typename[0]) if srsnameobj is not None: request['srsname'] = srsnameobj.id else: options = ", ".join( map(lambda x: x.id, self.contents[typename[0]].crsOptions)) raise ServiceException( "SRSNAME %s not supported. Options: %s" % (srsname, options)) else: request['srsname'] = str(srsname) # check featureid if featureid: request['featureid'] = ','.join(featureid) # bbox elif bbox and typename: request["bbox"] = self.getBBOXKVP(bbox, typename) # or filter elif filter and typename: request['filter'] = str(filter) assert len(typename) > 0 request['typename'] = ','.join(typename) if propertyname is not None: if not isinstance(propertyname, list): propertyname = [propertyname] request['propertyname'] = ','.join(propertyname) if featureversion is not None: request['featureversion'] = str(featureversion) if maxfeatures is not None: request['maxfeatures'] = str(maxfeatures) if startindex is not None: request['startindex'] = str(startindex) if outputFormat is not None: request["outputFormat"] = outputFormat data = urlencode(request) log.debug("Making request: %s?%s" % (base_url, data)) u = openURL(base_url, data, method, timeout=self.timeout) # check for service exceptions, rewrap, and return # We're going to assume that anything with a content-length > 32k # is data. We'll check anything smaller. try: length = int(u.info()['Content-Length']) have_read = False except (KeyError, AttributeError): data = u.read() have_read = True length = len(data) if length < 32000: if not have_read: data = u.read() try: tree = etree.fromstring(data) except BaseException: # Not XML return StringIO(data) else: if tree.tag == "{%s}ServiceExceptionReport" % namespaces["ogc"]: se = tree.find( nspath_eval('ServiceException', namespaces["ogc"])) raise ServiceException(str(se.text).strip()) else: return StringIO(data) else: if have_read: return StringIO(data) return u
def getfeature(self, typename=None, filter=None, bbox=None, featureid=None, featureversion=None, propertyname=['*'], maxfeatures=None, srsname=None, outputFormat=None, method='{http://www.opengis.net/wfs}Get', startindex=None): """Request and return feature data as a file-like object. Parameters ---------- typename : list List of typenames (string) filter : string XML-encoded OGC filter expression. bbox : tuple (left, bottom, right, top) in the feature type's coordinates. featureid : list List of unique feature ids (string) featureversion : string Default is most recent feature version. propertyname : list List of feature property names. '*' matches all. maxfeatures : int Maximum number of features to be returned. method : string Qualified name of the HTTP DCP method to use. srsname: string EPSG code to request the data in outputFormat: string (optional) Requested response format of the request. startindex: int (optional) Start position to return feature set (paging in combination with maxfeatures) There are 3 different modes of use 1) typename and bbox (simple spatial query) 2) typename and filter (more expressive) 3) featureid (direct access to known features) """ try: base_url = next( ( m.get('url') for m in self.getOperationByName('GetFeature').methods if m.get('type').lower() == method.lower() ) ) except StopIteration: base_url = self.url request = {'service': 'WFS', 'version': self.version, 'request': 'GetFeature'} # check featureid if featureid: request['featureid'] = ','.join(featureid) elif bbox and typename: request['bbox'] = ','.join([repr(x) for x in bbox]) elif filter and typename: request['filter'] = str(filter) if srsname: request['srsname'] = str(srsname) assert len(typename) > 0 request['typename'] = ','.join(typename) if propertyname: request['propertyname'] = ','.join(propertyname) if featureversion: request['featureversion'] = str(featureversion) if maxfeatures: request['maxfeatures'] = str(maxfeatures) if startindex: request['startindex'] = str(startindex) if outputFormat is not None: request["outputFormat"] = outputFormat data = urlencode(request) log.debug("Making request: %s?%s" % (base_url, data)) u = openURL(base_url, data, method, timeout=self.timeout) # check for service exceptions, rewrap, and return # We're going to assume that anything with a content-length > 32k # is data. We'll check anything smaller. try: length = int(u.info()['Content-Length']) have_read = False except (KeyError, AttributeError): data = u.read() have_read = True length = len(data) if length < 32000: if not have_read: data = u.read() try: tree = etree.fromstring(data) except BaseException: # Not XML return StringIO(data) else: if tree.tag == "{%s}ServiceExceptionReport" % OGC_NAMESPACE: se = tree.find(nspath('ServiceException', OGC_NAMESPACE)) raise ServiceException(str(se.text).strip()) else: return StringIO(data) else: if have_read: return StringIO(data) return u
def getfeature(self, typename=None, filter=None, bbox=None, featureid=None, featureversion=None, propertyname=['*'], maxfeatures=None, srsname=None, outputFormat=None, method='Get', startindex=None): """Request and return feature data as a file-like object. Parameters ---------- typename : list List of typenames (string) filter : string XML-encoded OGC filter expression. bbox : tuple (left, bottom, right, top) in the feature type's coordinates. featureid : list List of unique feature ids (string) featureversion : string Default is most recent feature version. propertyname : list List of feature property names. '*' matches all. maxfeatures : int Maximum number of features to be returned. method : string Qualified name of the HTTP DCP method to use. srsname: string EPSG code to request the data in outputFormat: string (optional) Requested response format of the request. startindex: int (optional) Start position to return feature set (paging in combination with maxfeatures) There are 3 different modes of use 1) typename and bbox (simple spatial query). It is assumed, that bbox coordinates are given *always* in the east,north order 2) typename and filter (more expressive) 3) featureid (direct access to known features) """ try: base_url = next( ( m.get('url') for m in self.getOperationByName('GetFeature').methods if m.get('type').lower() == method.lower() ) ) except StopIteration: base_url = self.url request = {'service': 'WFS', 'version': self.version, 'request': 'GetFeature'} if not isinstance(typename, list): typename = [typename] if srsname is not None: # check, if desired SRS is supported by the service for this typename if typename is not None: # convert srsname string to Crs object found in GetCaps srsnameobj = self.getSRS(srsname, typename[0]) if srsnameobj is not None: request['srsname'] = srsnameobj.id else: options = ", ".join(map(lambda x: x.id, self.contents[typename[0]].crsOptions)) raise ServiceException( "SRSNAME %s not supported. Options: %s" % (srsname, options) ) else: request['srsname'] = str(srsname) # check featureid if featureid: request['featureid'] = ','.join(featureid) # bbox elif bbox and typename: request["bbox"] = self.getBBOXKVP(bbox, typename) # or filter elif filter and typename: request['filter'] = str(filter) assert len(typename) > 0 request['typename'] = ','.join(typename) if propertyname is not None: if not isinstance(propertyname, list): propertyname = [propertyname] request['propertyname'] = ','.join(propertyname) if featureversion is not None: request['featureversion'] = str(featureversion) if maxfeatures is not None: request['maxfeatures'] = str(maxfeatures) if startindex is not None: request['startindex'] = str(startindex) if outputFormat is not None: request["outputFormat"] = outputFormat data = urlencode(request) log.debug("Making request: %s?%s" % (base_url, data)) u = openURL(base_url, data, method, timeout=self.timeout) # check for service exceptions, rewrap, and return # We're going to assume that anything with a content-length > 32k # is data. We'll check anything smaller. try: length = int(u.info()['Content-Length']) have_read = False except (KeyError, AttributeError): data = u.read() have_read = True length = len(data) if length < 32000: if not have_read: data = u.read() try: tree = etree.fromstring(data) except BaseException: # Not XML return StringIO(data) else: if tree.tag == "{%s}ServiceExceptionReport" % namespaces["ogc"]: se = tree.find(nspath_eval('ServiceException', namespaces["ogc"])) raise ServiceException(str(se.text).strip()) else: return StringIO(data) else: if have_read: return StringIO(data) return u
def getfeature(self, typename=None, filter=None, bbox=None, featureid=None, featureversion=None, propertyname=None, maxfeatures=None,storedQueryID=None, storedQueryParams={}, method='Get', outputFormat=None, startindex=None): """Request and return feature data as a file-like object. #TODO: NOTE: have changed property name from ['*'] to None - check the use of this in WFS 2.0 Parameters ---------- typename : list List of typenames (string) filter : string XML-encoded OGC filter expression. bbox : tuple (left, bottom, right, top) in the feature type's coordinates == (minx, miny, maxx, maxy) featureid : list List of unique feature ids (string) featureversion : string Default is most recent feature version. propertyname : list List of feature property names. '*' matches all. maxfeatures : int Maximum number of features to be returned. method : string Qualified name of the HTTP DCP method to use. outputFormat: string (optional) Requested response format of the request. startindex: int (optional) Start position to return feature set (paging in combination with maxfeatures) There are 3 different modes of use 1) typename and bbox (simple spatial query) 2) typename and filter (==query) (more expressive) 3) featureid (direct access to known features) """ url = data = None if typename and type(typename) == type(""): typename = [typename] if method.upper() == "GET": (url) = self.getGETGetFeatureRequest(typename, filter, bbox, featureid, featureversion, propertyname, maxfeatures, storedQueryID, storedQueryParams, outputFormat, 'Get', startindex) if log.isEnabledFor(logging.DEBUG): log.debug('GetFeature WFS GET url %s'% url) else: (url,data) = self.getPOSTGetFeatureRequest() # If method is 'Post', data will be None here u = urlopen(url, data, self.timeout) # check for service exceptions, rewrap, and return # We're going to assume that anything with a content-length > 32k # is data. We'll check anything smaller. try: length = int(u.info()['Content-Length']) have_read = False except KeyError: data = u.read() have_read = True length = len(data) if length < 32000: if not have_read: data = u.read() try: tree = etree.fromstring(data) except BaseException: # Not XML return StringIO(data) else: if tree.tag == "{%s}ServiceExceptionReport" % OGC_NAMESPACE: se = tree.find(nspath('ServiceException', OGC_NAMESPACE)) raise ServiceException(str(se.text).strip()) else: return StringIO(data) else: if have_read: return StringIO(data) return u
def getrecords(self, qtype=None, keywords=[], typenames='csw:Record', propertyname='csw:AnyText', bbox=None, esn='summary', sortby=None, outputschema=namespaces['csw'], format=outputformat, startposition=0, maxrecords=10, cql=None, xml=None, resulttype='results'): """ Construct and process a GetRecords request Parameters ---------- - qtype: type of resource to query (i.e. service, dataset) - keywords: list of keywords - typenames: the typeNames to query against (default is csw:Record) - propertyname: the PropertyName to Filter against - bbox: the bounding box of the spatial query in the form [minx,miny,maxx,maxy] - esn: the ElementSetName 'full', 'brief' or 'summary' (default is 'summary') - sortby: property to sort results on - outputschema: the outputSchema (default is 'http://www.opengis.net/cat/csw/2.0.2') - format: the outputFormat (default is 'application/xml') - startposition: requests a slice of the result set, starting at this position (default is 0) - maxrecords: the maximum number of records to return. No records are returned if 0 (default is 10) - cql: common query language text. Note this overrides bbox, qtype, keywords - xml: raw XML request. Note this overrides all other options - resulttype: the resultType 'hits', 'results', 'validate' (default is 'results') """ warnings.warn("""Please use the updated 'getrecords2' method instead of 'getrecords'. The 'getrecords' method will be upgraded to use the 'getrecords2' parameters in a future version of OWSLib.""") if xml is not None: self.request = etree.fromstring(xml) val = self.request.find(util.nspath_eval('csw:Query/csw:ElementSetName', namespaces)) if val is not None: esn = util.testXMLValue(val) else: # construct request node0 = self._setrootelement('csw:GetRecords') if etree.__name__ != 'lxml.etree': # apply nsmap manually node0.set('xmlns:ows', namespaces['ows']) node0.set('xmlns:gmd', namespaces['gmd']) node0.set('xmlns:dif', namespaces['dif']) node0.set('xmlns:fgdc', namespaces['fgdc']) node0.set('outputSchema', outputschema) node0.set('outputFormat', format) node0.set('version', self.version) node0.set('resultType', resulttype) node0.set('service', self.service) if startposition > 0: node0.set('startPosition', str(startposition)) node0.set('maxRecords', str(maxrecords)) node0.set(util.nspath_eval('xsi:schemaLocation', namespaces), schema_location) node1 = etree.SubElement(node0, util.nspath_eval('csw:Query', namespaces)) node1.set('typeNames', typenames) etree.SubElement(node1, util.nspath_eval('csw:ElementSetName', namespaces)).text = esn self._setconstraint(node1, qtype, propertyname, keywords, bbox, cql, None) if sortby is not None: fes.setsortby(node1, sortby) self.request = node0 self._invoke() if self.exceptionreport is None: self.results = {} # process search results attributes val = self._exml.find(util.nspath_eval('csw:SearchResults', namespaces)).attrib.get('numberOfRecordsMatched') self.results['matches'] = int(util.testXMLValue(val, True)) val = self._exml.find(util.nspath_eval('csw:SearchResults', namespaces)).attrib.get('numberOfRecordsReturned') self.results['returned'] = int(util.testXMLValue(val, True)) val = self._exml.find(util.nspath_eval('csw:SearchResults', namespaces)).attrib.get('nextRecord') self.results['nextrecord'] = int(util.testXMLValue(val, True)) # process list of matching records self.records = OrderedDict() self._parserecords(outputschema, esn)
def getmap(self, layers=None, styles=None, srs=None, bbox=None, format=None, size=None, time=None, transparent=False, bgcolor='#FFFFFF', exceptions='XML', method='Get', **kwargs): """Request and return an image from the WMS as a file-like object. Parameters ---------- layers : list List of content layer names. styles : list Optional list of named styles, must be the same length as the layers list. srs : string A spatial reference system identifier. bbox : tuple (left, bottom, right, top) in srs units. format : string Output image format such as 'image/jpeg'. size : tuple (width, height) in pixels. transparent : bool Optional. Transparent background if True. bgcolor : string Optional. Image background color. method : string Optional. HTTP DCP method name: Get or Post. **kwargs : extra arguments anything else e.g. vendor specific parameters Example ------- >>> wms = WebMapService('http://webservices.nationalatlas.gov/wms/1million', version='1.3.0') >>> img = wms.getmap(layers=['airports1m'],\ styles=['default'],\ srs='EPSG:4326',\ bbox=(-176.646, 17.7016, -64.8017, 71.2854),\ size=(300, 300),\ format='image/jpeg',\ transparent=True) >>> out = open('example.jpg.jpg', 'wb') >>> out.write(img.read()) >>> out.close() """ try: base_url = next((m.get('url') for m in self.getOperationByName('GetMap').methods if m.get('type').lower() == method.lower())) except StopIteration: base_url = self.url request = {'version': self.version, 'request': 'GetMap'} # check layers and styles assert len(layers) > 0 request['layers'] = ','.join(layers) if styles: assert len(styles) == len(layers) request['styles'] = ','.join(styles) else: request['styles'] = '' # size request['width'] = str(size[0]) request['height'] = str(size[1]) request['crs'] = str(srs) request['bbox'] = ','.join([repr(x) for x in bbox]) request['format'] = str(format) request['transparent'] = str(transparent).upper() request['bgcolor'] = '0x' + bgcolor[1:7] request['exceptions'] = str(exceptions) if time is not None: request['time'] = str(time) if kwargs: for kw in kwargs: request[kw] = kwargs[kw] data = urlencode(request) print(data) u = openURL(base_url, data, method, username=self.username, password=self.password) # check for service exceptions, and return # error: AttributeError: 'RereadableURL' object has no attribute 'info' if u.info()['Content-Type'] in [ 'application/vnd.ogc.se_xml', 'text/xml' ]: se_xml = u.read() print(se_xml) se_tree = etree.fromstring(se_xml) # TODO: add the ogc namespace for this err_message = unicode( se_tree.find( '{http://www.opengis.net/ogc}ServiceExceptionReport').text ).strip() raise ServiceException(err_message, se_xml) return u