def __init__(self): inputs = [ LiteralInput('input1', 'Input1 number', default='100', data_type='integer'), LiteralInput('input2', 'Input2 number', default='200', data_type='integer'), ] outputs = [ LiteralOutput('output1', 'Output1 add 1 result', data_type='string'), LiteralOutput('output2', 'Output2 substract 1 result', data_type='string'), ] super(Dummy, self).__init__( self._handler, identifier='dummyprocess', title="Dummy Process", abstract="DummyProcess to check the WPS structure", version="2.0", inputs=inputs, outputs=outputs, store_supported=True, status_supported=True )
def test_literal_output(self): literal = LiteralOutput('literal', 'Literal foo', abstract='Description', keywords=['kw1', 'kw2'], uoms=['metre']) doc = literal.describe_xml() [output] = xpath_ns(doc, '/Output') [identifier] = xpath_ns(doc, '/Output/ows:Identifier') [abstract] = xpath_ns(doc, '/Output/ows:Abstract') [keywords] = xpath_ns(doc, '/Output/ows:Keywords') kws = xpath_ns(keywords, './ows:Keyword') [data_type] = xpath_ns(doc, '/Output/LiteralOutput/ows:DataType') [uoms] = xpath_ns(doc, '/Output/LiteralOutput/UOMs') [default_uom] = xpath_ns(uoms, './Default/ows:UOM') supported_uoms = xpath_ns(uoms, './Supported/ows:UOM') assert output is not None assert identifier.text == 'literal' assert abstract.text == 'Description' assert keywords is not None assert len(kws) == 2 assert data_type.attrib['{{{}}}reference'.format( NAMESPACES['ows'])] == OGCTYPE['string'] assert uoms is not None assert default_uom.text == 'metre' assert default_uom.attrib['{{{}}}reference'.format( NAMESPACES['ows'])] == OGCUNIT['metre'] assert len(supported_uoms) == 1
def __init__(self): # inputs (basename, layername und expression) inputs = [LiteralInput('start1', 'Start date (eg. 2020-05-01)', data_type='string'), LiteralInput('end1', 'End date (eg. 2020-05-04)', data_type='string'), LiteralInput('start2', 'Start date (eg. 2020-05-01)', data_type='string'), LiteralInput('end2', 'End date (eg. 2020-05-04)', data_type='string'), # LiteralInput('expression', 'Expression (eg. bla blubb)', data_type='string') ] outputs = [LiteralOutput('stats1', 'Computed LST statistics', data_type='string'), LiteralOutput('stats2', 'Computed ndvi statistics', data_type='string') ] # Link for Execution! # http://localhost:5000/wps?request=Execute&service=WPS&identifier=tempalg&version=1.0.0&datainputs=start1=2020-05-01;end1=2020-05-04;start2=2020-05-01;end2=2020-05-04 super(TempAlg, self).__init__( self._handler, identifier='tempalg', version='0.1', title="Temporal Algorithms", abstract='Temporal Algorithms for SpaceTimeCubes', profile='', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True, grass_location="/home/user/Desktop/GEO450_main_dir/grass_dir/GEO450_test1" )
def output_formats(self): return [ LiteralOutput("image", "WOfS Pixel Drill Preview"), LiteralOutput("url", "WOfS Pixel Drill Graph"), ComplexOutput('timeseries', 'Timeseries Drill', supported_formats=[FORMATS['output_json']]) ]
def output_formats(self): return [ LiteralOutput("image", "Fractional Cover Drill Preview"), LiteralOutput("url", "Fractional Cover Drill Chart"), ComplexOutput('timeseries', 'Fractional Cover Polygon Drill Timeseries', supported_formats=[FORMATS['output_json']]) ]
def __init__(self): # From pywps4 code : time_format = '%Y-%m-%dT%H:%M:%S%z' # Is that a bug? %z should be %Z # Using 'string' data_type until this is corrected. cal_abs = 'If left unspecified, taken from NetCDF file time variable.' inputs = [ LiteralInput('initial_date', 'Initial date of the period', data_type='string', abstract='Format must be %Y-%m-%dT%H:%M:%S'), LiteralInput('final_date', 'Final date of the period', data_type='string', abstract='Format must be %Y-%m-%dT%H:%M:%S'), LiteralInput('opendap_url', 'OPeNDAP url to a NetCDF file', data_type='string', abstract='OPeNDAP url to a NetCDF file'), LiteralInput('calendar', 'NetCDF calendar type', data_type='string', abstract=cal_abs, default='gregorian', min_occurs=0) ] title_ini = 'Initial time index of the period in the NetCDF file' title_fin = 'Final time index of the period in the NetCDF file' abstract_fin = title_fin + '. The final index is inclusive.' outputs = [ LiteralOutput('initial_index', title_ini, data_type='integer', abstract=title_ini), LiteralOutput('final_index', title_fin, data_type='integer', abstract=abstract_fin) ] super(Period2Indices, self).__init__(self._handler, identifier='period2indices', title='NetCDF time indices from a period', abstract='The final index is inclusive.', version='0.1', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [LiteralInput('start', 'Start date (eg. 2019-03-01)', data_type='string'), LiteralInput('end', 'End date (eg. 2019-04-01)', data_type='string'), LiteralInput('start2', 'Start date 2 (eg. 2019-03-01)', data_type='string'), LiteralInput('end2', 'End date 2 (eg. 2019-04-01)', data_type='string'), ] outputs = [LiteralOutput('stats', 'Computed ndvi statistics', data_type='string') ] super(ndvi_index, self).__init__( self._handler, identifier='ndvi', version='0.1', title="Sentinel-2 NDVI Calculator", abstract='The Process will compute the average NDVI ' \ 'for a given time-period over an area near Jena', profile='', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True, grass_location="C:\Sentinel2Project\GrassGIS\PERMANENT" )
def __init__(self): inputs = [ LiteralInput(identifier='first_arg', title='first Input', data_type='integer', abstract="Dividend"), LiteralInput(identifier='second_arg', title='second Input', data_type='integer', abstract="Divisor") ] outputs = [ LiteralOutput(identifier='response', title='Output response', data_type='integer', abstract="Quotient") ] super(Division, self).__init__( self.handler, identifier='division', title='Division Process', abstract='Dividiert zwei eingegebene ganze Zahlen (ohne Rest)', version='1.0.0', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [ LiteralInput('inputa', 'Input 1', data_type='float', abstract='Enter Input 1', default="2.0"), LiteralInput('inputb', 'Input 2', data_type='float', abstract='Enter Input 2', default="3.0"), LiteralInput('operator', 'Operator', data_type='string', abstract='Choose a binary Operator', default='add', allowed_values=['add', 'substract', 'divide', 'multipy'])] outputs = [ LiteralOutput('output', 'Binary operator result', data_type='float')] super(BinaryOperator, self).__init__( self._handler, identifier='binaryoperatorfornumbers', title='Binary Operator for Numbers', abstract='Performs operation on two numbers and returns the answer.\ This example process is taken from Climate4Impact.', metadata=[ Metadata('Birdhouse', 'http://bird-house.github.io/'), Metadata('User Guide', 'http://emu.readthedocs.io/en/latest/'), Metadata('Climate4Impact', 'https://dev.climate4impact.eu')], version='1.0', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True )
def __init__(self): inputs = [ ComplexInput('filesIn', 'Input NetCDF Files URL', abstract='Input NetCDF Files URL.', supported_formats=[Format('JSON')], mode=MODE.STRICT) ] outputs = [ LiteralOutput('output', 'Output response', abstract='Output response.', data_type='string') ] super(Repackage, self).__init__( self._handler, identifier='repackage', title='Repackage', abstract='Repackage a list of NetCDF files.' 'For now returns an ncdump of the merge of the input files.', metadata=[ Metadata('PyWPS', 'https://pywps.org/'), Metadata('Birdhouse', 'http://bird-house.github.io/') ], version='0.1', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): self.status_percentage_steps = dict( common_status_percentages, **{"load_rdata": 10}, ) inputs = avail_indices_inputs outputs = [ LiteralOutput( "avail_processes", "Available processes dictionary", abstract= "Available climdex indices (values) and the processes to use to compute them (keys)", data_type="string", ), ] super(GetIndices, self).__init__( self._handler, identifier="climdex_get_available_indices", title="Climdex Get Available Indices", abstract= "Returns the names of all the indices which may be computed or, if get_function_names is TRUE, the names of the functions corresponding to the indices.", metadata=[ Metadata("NetCDF processing"), Metadata("Climate Data Operations"), Metadata("PyWPS", "https://pywps.org/"), Metadata("Birdhouse", "http://bird-house.github.io/"), Metadata("PyWPS Demo", "https://pywps-demo.readthedocs.io/en/latest/"), ], inputs=inputs, outputs=outputs, store_supported=True, status_supported=True, )
def __init__(self): # init process inputs = [ LiteralInput('outlet_x', 'Outlet Longitude', data_type='float'), LiteralInput('outlet_y', 'Outlet Latitude', data_type='float') ] outputs = [ ComplexOutput('watershed', 'Delineated Watershed', supported_formats=[Format('text/xml')]), ComplexOutput('snappoint', 'Snapped outlet point', supported_formats=[Format('text/xml')]), LiteralOutput('message', 'Processing message', data_type='string') ] super(watersheddelineationprocess, self).__init__( self._handler, identifier= 'watersheddelineationprocess', # must be same, as filename version='1.0', title="Watershed delineation process", abstract= 'This process snap a given point to nearest stream and perform watershed delineation function using GRASS within DR country area', profile='', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [ LiteralInput('name', 'Your name', abstract='Please enter your name.', keywords=['name', 'firstname'], data_type='string'),] outputs = [ LiteralOutput('output', 'Output response', abstract='A friendly Hello from us.', keywords=['output', 'result', 'response'], data_type='string')] super(SayHello, self).__init__( self._handler, identifier='hello', title='Say Hello', abstract='Just says a friendly Hello.' 'Returns a literal string output with Hello plus the inputed name.', keywords=['hello', 'demo'], metadata=[ Metadata('PyWPS', 'https://pywps.org/'), Metadata('Birdhouse', 'http://bird-house.github.io/'), Metadata('PyWPS Demo', 'https://pywps-demo.readthedocs.io/en/latest/'), Metadata('Emu: PyWPS examples', 'https://emu.readthedocs.io/en/latest/'), ], version='1.5', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True )
def __init__(self): inputs = [ LiteralInput('start', 'Start date (eg. 2019-03-01)', data_type='string'), LiteralInput('end', 'End date (eg. 2019-04-01)', data_type='string') ] outputs = [ LiteralOutput('stats', 'Computed LST statistics', data_type='string') ] super(ModisV1, self).__init__( self._handler, identifier='modis-v1', version='0.1', title="Modis process (v1)", abstract='The process uses the GRASS GIS to compute LST ' \ 'statistics for given period in 2019 for Germany', profile='', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True, grass_location="/home/user/grassdata/germany-modis" )
def __init__(self): inputs = [ LiteralInput( 'input', 'Input File (http://thredds.met.no/thredds/dodsC/arome25/arome_metcoop_default2_5km_latest.nc)', data_type='string', min_occurs=1, max_occurs=1), LiteralInput('variable', 'Variable to plot', data_type='string', min_occurs=0, max_occurs=1) ] outputs = [LiteralOutput('plot', 'bokeh plot', data_type='string')] super(TsPlot, self).__init__( self._handler, identifier='tsplot', title='TsPlot', abstract= 'Tak e a Timne series data (Variable, Time) as netcdf with known structure, \ ' 'and return html and js to build an interactive html plot using the bokeh llibrary.', version='1.0', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [ LiteralInput('start', 'Start date (eg. 2019-03-01)', data_type='string'), LiteralInput('end', 'End date (eg. 2019-04-01)', data_type='string') ] outputs = [ LiteralOutput('stats', 'Computed ndvi statistics', data_type='string') ] super(Sen2_index, self).__init__( self._handler, identifier='sen2_index', version='0.1', title="Sentinel-2 NDVI Calculator", abstract='The Process will compute the average NDVI ' \ 'for a given time-period over an area near Jena', profile='', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True, grass_location="/home/robin/grassdata/jena_roda" )
def __init__(self): self.status_percentage_steps = { # Used to test 'log_handler' "start": 0, "complete": 100, } inputs = [ LiteralInput( "string", "String", abstract="Enter string.", data_type="string", ) ] outputs = [ LiteralOutput( "output", "Output response", abstract="Outputs string entered.", data_type="string", ) ] super(TestProcess, self).__init__( self._handler, identifier="test_process", title="Test Process", abstract= "A simple process that returns the string that was inputted.", inputs=inputs, outputs=outputs, store_supported=True, status_supported=True, )
def __init__(self): """Inputs and outputs for run_nc2tiff.sh sript.""" inputs = [ LiteralInput('zipdir', 'input zip path', abstract=""" Input Sentinel 1 zip file path. """, data_type='string', min_occurs=1) ] outputs = [ LiteralOutput( 'output_dir', 'Workflow data volume path', data_type='string', abstract=""" Path to the output png file. """, ) ] super(CreateTiff, self).__init__( identifier=os.path.basename(os.path.dirname(__file__)), abstract=""" Sample GeoTiff generation service. """, version='0.1', title="SSWind Sample Service: GeoTiff creation", profile='', metadata=[Metadata('Testing')], inputs=inputs, outputs=outputs, )
def __init__(self): inputs = [ LiteralInput(identifier='arg', title='Argument', data_type='integer', abstract="Argument") ] outputs = [ LiteralOutput(identifier='response', title='Output response', data_type='integer', abstract="Summe") ] super(Factorial, self).__init__( self.handler, identifier='factorial', title='Factorial Process', abstract= 'Berechnet die Fakultät Funktion einer eingegebenen ganzen Zahl', version='1.0.0', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [ LiteralInput('delay', 'Delay between every update', default='1', data_type='float') ] outputs = [ LiteralOutput('sleep_output', 'Sleep Output', data_type='string') ] super(Sleep, self).__init__( self._handler, identifier='sleep', version='1.0', title='Sleep Process', abstract='Testing a long running process, in the sleep.' 'This process will sleep for a given delay or 10 seconds if not a valid value.', profile='', metadata=[ Metadata('PyWPS Demo', 'https://pywps-demo.readthedocs.io/en/latest/'), ], inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [ LiteralInput('delay', 'Delay between every update', data_type='float') ] outputs = [ LiteralOutput('sleep_output', 'Sleep Output', data_type='string') ] super(Sleep, self).__init__( self._handler, identifier='sleep', version='None', title='Sleep Process', abstract="The process will sleep for a given delay \ or 10 seconds if not a valid value", profile='', metadata=[Metadata('Sleep'), Metadata('Wait'), Metadata('Delay')], inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [ LiteralInput('point_x', 'Pour Point Longitude', data_type='float'), LiteralInput('point_y', 'Pour Point Latitude', data_type='float'), LiteralInput('water_level', 'Water level at pour point', data_type='float'), ComplexInput('max_boundary', 'Maximum Reservior Boundary', supported_formats=[Format('text/xml')]) ] outputs = [ LiteralOutput('lake_volume', 'Reservoir volume in cubic meters', data_type='float'), ComplexOutput('lake_boundary', 'Reservoir boundary polygon', supported_formats=[Format('text/xml')]) ] super(reservoircalculationprocess, self).__init__( self._handler, identifier='reservoircalculationprocess', title='Reservoir Calculation Service', abstract= 'This process returns the boundary and storage capacity of a reservoir based on a given pour point location, an aimed water level, and maximum reservoir boundary polygon', version='1.0', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [ ComplexInput('polygon', 'Region definition', abstract="A polygon defining a region.", supported_formats=[ FORMATS.GML, ]), ] outputs = [ LiteralOutput( 'output', 'The centroid of the polygon geometry.', abstract= "The coordinates of the polygon's approximate centroid.", ) ] super(PolyCentroid, self).__init__( self._handler, identifier='poly_centroid', title="Approximate centroid of a polygon.", abstract= "Return the polygon's centroid coordinates. If the geometry contains multiple polygons, " "only the centroid of the first one will be computed. Do not use for serious computations" ", this is only a test process and uses a crude approximation. ", version="1.0", inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self, **kw): # remove duplicates/unsupported keywords title = kw.pop("title", kw.get("identifier")) version = kw.pop("version", "0.0") kw.pop("inputs", None) kw.pop("outputs", None) kw.pop("payload", None) kw.pop("package", None) super(WpsTestProcess, self).__init__(self._handler, title=title, version=version, inputs=[ LiteralInput("test_input", "Input Request", data_type="string") ], outputs=[ LiteralOutput("test_output", "Output response", data_type="string") ], store_supported=True, status_supported=True, **kw)
def create_app(): service = Service(processes=[ Process(say_hello, inputs=[LiteralInput('name', 'string')], outputs=[LiteralOutput('response', 'string')]), Process(feature_count, inputs=[ComplexInput('layer', [Format(Formats.GML)])], outputs=[ComplexInput('layer', [Format(Formats.GML)])]), Process(centroids, inputs=[ComplexInput('layer', [Format(Formats.GML)])]), ]) app = flask.Flask(__name__) @app.route('/') def home(): url = flask.url_for('wps', _external=True) return flask.render_template('home.html', url=url) @app.route('/wps', methods=['GET', 'POST']) def wps(): return service @app.route('/datafile/<uuid>') def datafile(uuid): for data_file in recent_data_files: if data_file['uuid'] == uuid: return flask.Response(data_file['bytes']) else: flask.abort(404) return app
def __init__(self): inputs = [ LiteralInput('input 1', 'Input1 number', default='100', data_type='integer'), ComplexInput('input-2', 'json input', supported_formats=[FORMATS.JSON, ]), ] outputs = [ LiteralOutput('output.1', 'Add 1 to `input 1`.', data_type='float'), ComplexOutput('output 2', 'Same thing as input-2.', supported_formats=[FORMATS.JSON, ]), ] super(NonPyID, self).__init__( self._handler, identifier='non.py-id', # TODO:fails with pywps: u'fake.process-for testing &é;' title="Dummy process including non-pythonic identifiers", abstract="Dummy process whose process, input and output identifiers include characters not allowed " "in Python.", version="1.0", inputs=inputs, outputs=outputs, store_supported=True, status_supported=True )
def try_connect(self, graph, linked_input, downstream_task, downstream_task_input): """ Override TaskPE fct. See TaskPE.try_connect for details. The MapPE uses the downstream task input format to set it's own output format and it's set upon connection """ # Set the supported output description which is the same as the downstream task supported input if TaskPE.try_connect(self, graph, linked_input, downstream_task, downstream_task_input): down_task_in_desc = downstream_task.get_input_desc( downstream_task_input) params = dict(identifier=self.MAP_OUTPUT, title=self.MAP_OUTPUT) if down_task_in_desc.dataType == 'ComplexData': params['supported_formats'] = [ Format(mime_type=down_task_in_desc.defaultValue.mimeType, schema=down_task_in_desc.defaultValue.schema, encoding=down_task_in_desc.defaultValue.encoding) ] params['as_reference'] = False self.output_desc = Output( ComplexOutput(**params).describe_xml()) self.output_desc.mimeType = down_task_in_desc.defaultValue.mimeType elif down_task_in_desc.dataType == 'BoundingBoxData': params['crss'] = down_task_in_desc.supportedValues params['as_reference'] = False self.output_desc = Output( BoundingBoxOutput(**params).describe_xml()) else: params['data_type'] = down_task_in_desc.dataType self.output_desc = Output( LiteralOutput(**params).describe_xml()) return True return False
def __init__(self): inputs = [ LiteralInput(identifier='first_arg', title='first Input', data_type='integer', abstract="Erster Summand"), LiteralInput(identifier='second_arg', title='second Input', data_type='integer', abstract="Zweiter summand") ] outputs = [ LiteralOutput(identifier='response', title='Output response', data_type='integer', abstract="Summe") ] super(Addition, self).__init__( self.handler, identifier='addition', title='Addition Process', abstract='Addiert zwei eingegebene ganze Zahlen (integers)', version='1.0.0', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True)
def __init__(self): inputs = [ LiteralInput('name', 'Your name', abstract='Please enter your name.', data_type='string')] outputs = [ LiteralOutput('output', 'Output response', abstract='A friendly Hello from us.', data_type='string')] super(SayHello, self).__init__( self._handler, identifier='hello', title='Say Hello', abstract='Just says a friendly Hello.' 'Returns a literal string output with Hello plus the inputed name.', metadata=[ Metadata('User Guide', 'https://emu.readthedocs.io/en/latest/processes.html'), # noqa Metadata('PyWPS Demo', 'https://pywps-demo.readthedocs.io/en/latest/'), ], version='1.5', inputs=inputs, outputs=outputs, store_supported=True, status_supported=True )
def __init__(self): inputs = [ LiteralInput('delay', 'Delay between every update', default='1', data_type='float') ] outputs = [ LiteralOutput('output', 'Nap Output', data_type='string') ] super(Nap, self).__init__( self._handler, identifier='nap', version='1.0', title='Afternoon Nap (supports sync calls only)', abstract='This process will have a short nap for a given delay or 1 second if not a valid value.\ This procces only supports synchronous WPS requests ... \ so, make sure the nap does not take to long.', profile='', metadata=[ Metadata('Birdhouse', 'http://bird-house.github.io/'), Metadata('User Guide', 'http://emu.readthedocs.io/en/latest/')], inputs=inputs, outputs=outputs, store_supported=False, status_supported=False )
def test_literal_output(self): literal = LiteralOutput('literal', 'Literal foo', uoms=['metre']) doc = literal.describe_xml() [output] = xpath_ns(doc, '/Output') [identifier] = xpath_ns(doc, '/Output/ows:Identifier') [data_type] = xpath_ns(doc, '/Output/LiteralOutput/ows:DataType') [uoms] = xpath_ns(doc, '/Output/LiteralOutput/UOMs') [default_uom] = xpath_ns(uoms, './Default/ows:UOM') supported_uoms = xpath_ns(uoms, './Supported/ows:UOM') assert output is not None assert identifier.text == 'literal' assert data_type.attrib['{%s}reference' % NAMESPACES['ows']] == OGCTYPE['string'] assert uoms is not None assert default_uom.text == 'metre' assert default_uom.attrib['{%s}reference' % NAMESPACES['ows']] == OGCUNIT['metre'] assert len(supported_uoms) == 1
def test_literal_output(self): literal = LiteralOutput("literal", "Literal foo", uoms=["metre"]) doc = literal.describe_xml() [output] = xpath_ns(doc, "/Output") [identifier] = xpath_ns(doc, "/Output/ows:Identifier") [data_type] = xpath_ns(doc, "/Output/LiteralOutput/ows:DataType") [uoms] = xpath_ns(doc, "/Output/LiteralOutput/UOMs") [default_uom] = xpath_ns(uoms, "./Default/ows:UOM") supported_uoms = xpath_ns(uoms, "./Supported/ows:UOM") assert output is not None assert identifier.text == "literal" assert data_type.attrib["{%s}reference" % NAMESPACES["ows"]] == OGCTYPE["string"] assert uoms is not None assert default_uom.text == "metre" assert default_uom.attrib["{%s}reference" % NAMESPACES["ows"]] == OGCUNIT["metre"] assert len(supported_uoms) == 1
def test_literal_output(self): literal = LiteralOutput('literal', 'Literal foo', abstract='Description', keywords=['kw1', 'kw2'], uoms=['metre']) doc = literal.describe_xml() [output] = xpath_ns(doc, '/Output') [identifier] = xpath_ns(doc, '/Output/ows:Identifier') [abstract] = xpath_ns(doc, '/Output/ows:Abstract') [keywords] = xpath_ns(doc, '/Output/ows:Keywords') kws = xpath_ns(keywords, './ows:Keyword') [data_type] = xpath_ns(doc, '/Output/LiteralOutput/ows:DataType') [uoms] = xpath_ns(doc, '/Output/LiteralOutput/UOMs') [default_uom] = xpath_ns(uoms, './Default/ows:UOM') supported_uoms = xpath_ns(uoms, './Supported/ows:UOM') assert output is not None assert identifier.text == 'literal' assert abstract.text == 'Description' assert keywords is not None assert len(kws) == 2 assert data_type.attrib['{{{}}}reference'.format(NAMESPACES['ows'])] == OGCTYPE['string'] assert uoms is not None assert default_uom.text == 'metre' assert default_uom.attrib['{{{}}}reference'.format(NAMESPACES['ows'])] == OGCUNIT['metre'] assert len(supported_uoms) == 1