From 07f4bb5b340182c011307c4546db77b35b8dd911 Mon Sep 17 00:00:00 2001 From: David Huard Date: Sun, 9 Feb 2020 10:35:11 -0500 Subject: [PATCH 01/16] Add NcML to supported FORMATS (#515) * added ncml to supported formats * added ncml schema --- pywps/inout/formats/__init__.py | 3 +- pywps/schemas/ncml/2.2/ncml-2.2.xsd | 288 ++++++++++++++++++++++++++++ 2 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 pywps/schemas/ncml/2.2/ncml-2.2.xsd diff --git a/pywps/inout/formats/__init__.py b/pywps/inout/formats/__init__.py index e872e6fc6..de86d3b22 100644 --- a/pywps/inout/formats/__init__.py +++ b/pywps/inout/formats/__init__.py @@ -18,7 +18,7 @@ _FORMATS = namedtuple('FORMATS', 'GEOJSON, JSON, SHP, GML, GPX, METALINK, META4, KML, KMZ, GEOTIFF,' 'WCS, WCS100, WCS110, WCS20, WFS, WFS100,' 'WFS110, WFS20, WMS, WMS130, WMS110,' - 'WMS100, TEXT, DODS, NETCDF, LAZ, LAS, ZIP,' + 'WMS100, TEXT, DODS, NETCDF, NCML, LAZ, LAS, ZIP,' 'XML') @@ -188,6 +188,7 @@ def json(self, jsonin): Format('text/plain', extension='.txt'), Format('application/x-ogc-dods', extension='.nc'), Format('application/x-netcdf', extension='.nc', encoding='base64'), + Format('application/ncML+xml', extension='.ncml', schema="ncml/2.2/ncml-2.2.xsd"), Format('application/octet-stream', extension='.laz'), Format('application/octet-stream', extension='.las'), Format('application/zip', extension='.zip', encoding='base64'), diff --git a/pywps/schemas/ncml/2.2/ncml-2.2.xsd b/pywps/schemas/ncml/2.2/ncml-2.2.xsd new file mode 100644 index 000000000..92540679f --- /dev/null +++ b/pywps/schemas/ncml/2.2/ncml-2.2.xsd @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 73bf3a34a0099a72ab5ea869aac3ba4866844b65 Mon Sep 17 00:00:00 2001 From: Pingu Carsti Date: Wed, 12 Feb 2020 15:29:17 +0100 Subject: [PATCH 02/16] fix tests with language option --- tests/test_capabilities.py | 7 ++++--- tests/test_describe.py | 7 ++++--- tests/test_execute.py | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/test_capabilities.py b/tests/test_capabilities.py index 1527aa622..98dc8bfe8 100644 --- a/tests/test_capabilities.py +++ b/tests/test_capabilities.py @@ -6,7 +6,7 @@ import unittest import lxml import lxml.etree -from pywps.configuration import CONFIG +from pywps import configuration from pywps.app import Process, Service from pywps.app.Common import Metadata from pywps import get_ElementMakerForVersion @@ -139,7 +139,8 @@ def test_version2(self): class CapabilitiesTranslationsTest(unittest.TestCase): def setUp(self): - CONFIG.set('server', 'language', 'en-US,fr-CA') + configuration.load_configuration() + configuration.CONFIG.set('server', 'language', 'en-US,fr-CA') self.client = client_for( Service( processes=[ @@ -162,7 +163,7 @@ def setUp(self): ) def tearDown(self): - CONFIG.set('server', 'language', 'en-US') + configuration.CONFIG.set('server', 'language', 'en-US') def test_get_translated(self): resp = self.client.get('?Request=GetCapabilities&service=wps&language=fr-CA') diff --git a/tests/test_describe.py b/tests/test_describe.py index bca5984fb..047aec1a8 100644 --- a/tests/test_describe.py +++ b/tests/test_describe.py @@ -13,7 +13,7 @@ from pywps.app.Common import Metadata from pywps.inout.literaltypes import AllowedValue from pywps.validator.allowed_value import ALLOWEDVALUETYPE -from pywps.configuration import CONFIG +from pywps import configuration from pywps.tests import assert_pywps_version, client_for @@ -141,7 +141,8 @@ def test_post_two_args(self): class DescribeProcessTranslationsTest(unittest.TestCase): def setUp(self): - CONFIG.set('server', 'language', 'en-US,fr-CA') + configuration.get_config_value('server', 'language') + configuration.CONFIG.set('server', 'language', 'en-US,fr-CA') self.client = client_for( Service( processes=[ @@ -196,7 +197,7 @@ def setUp(self): ) def tearDown(self): - CONFIG.set('server', 'language', 'en-US') + configuration.CONFIG.set('server', 'language', 'en-US') def test_get_describe_translations(self): resp = self.client.get('?Request=DescribeProcess&service=wps&version=1.0.0&identifier=all&language=fr-CA') diff --git a/tests/test_execute.py b/tests/test_execute.py index 23ed22d15..0e4afb37f 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -19,7 +19,7 @@ from pywps.app.basic import get_xpath_ns from pywps._compat import text_type from pywps.tests import client_for, assert_response_success -from pywps.configuration import CONFIG +from pywps import configuration from pywps._compat import PY2 from pywps._compat import StringIO @@ -503,10 +503,11 @@ def test_output_response_dataType(self): class ExecuteTranslationsTest(unittest.TestCase): def setUp(self): - CONFIG.set('server', 'language', 'en-US,fr-CA') + configuration.get_config_value('server', 'language') + configuration.CONFIG.set('server', 'language', 'en-US,fr-CA') def tearDown(self): - CONFIG.set('server', 'language', 'en-US') + configuration.CONFIG.set('server', 'language', 'en-US') def test_translations(self): client = client_for(Service(processes=[create_translated_greeter()])) From e7adf660e758e3e3b718cc066b76c7fbcae49d47 Mon Sep 17 00:00:00 2001 From: MacPingu Date: Thu, 13 Feb 2020 14:43:43 +0100 Subject: [PATCH 03/16] Issue 477 skip py27 (#520) * removed PY2 usage * removed flufl.enum * removed pathlib dependency --- debian/control | 2 +- pywps/_compat.py | 30 ------------- pywps/app/Process.py | 8 ++-- pywps/app/Service.py | 9 ++-- pywps/app/WPSRequest.py | 15 ++----- pywps/exceptions.py | 31 +++++++------- pywps/ext_autodoc.py | 12 ++---- pywps/inout/basic.py | 37 ++++++++-------- pywps/inout/inputs.py | 3 +- pywps/inout/literaltypes.py | 9 +--- pywps/inout/outputs.py | 2 +- pywps/inout/storage/__init__.py | 4 +- pywps/inout/storage/file.py | 2 +- pywps/inout/storage/implementationbuilder.py | 4 +- pywps/response/__init__.py | 2 +- pywps/response/execute.py | 10 +---- pywps/validator/complexvalidator.py | 1 + pywps/wpsserver.py | 4 +- requirements-dev.txt | 1 - tests/test_execute.py | 21 ++++------ tests/test_filestorage.py | 2 +- tests/test_inout.py | 44 +++++++------------- tests/test_s3storage.py | 11 ++--- tox.ini | 5 --- 24 files changed, 88 insertions(+), 181 deletions(-) delete mode 100644 pywps/_compat.py diff --git a/debian/control b/debian/control index 2d169b7a9..045253cbe 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Vcs-Git: https://github.com/geopython/pywps.git Package: python-pywps Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, python-pkg-resources, python-dateutil, python-flufl.enum, python-jsonschema, python-lxml, python-owslib, python-werkzeug +Depends: ${misc:Depends}, ${python:Depends}, python-pkg-resources, python-dateutil, python-jsonschema, python-lxml, python-owslib, python-werkzeug Suggests: grass, apache2, apache Homepage: https://pywps.org Description: OGC Web Processing Service (WPS) Implementation diff --git a/pywps/_compat.py b/pywps/_compat.py deleted file mode 100644 index cbd65d171..000000000 --- a/pywps/_compat.py +++ /dev/null @@ -1,30 +0,0 @@ -################################################################## -# Copyright 2018 Open Source Geospatial Foundation and others # -# licensed under MIT, Please consult LICENSE.txt for details # -################################################################## - -import logging -import sys - -__author__ = "Alex Morega" - -LOGGER = logging.getLogger('PYWPS') -PY2 = sys.version_info[0] == 2 - -if PY2: - LOGGER.debug('Python 2.x') - text_type = unicode # noqa - from StringIO import StringIO - from flufl.enum import Enum - from urlparse import urlparse - from urlparse import urljoin - from urllib2 import urlopen - -else: - LOGGER.debug('Python 3.x') - text_type = str - from io import StringIO - from enum import Enum - from urllib.parse import urlparse - from urllib.parse import urljoin - from urllib.request import urlopen diff --git a/pywps/app/Process.py b/pywps/app/Process.py index dd604d15c..32790cee3 100644 --- a/pywps/app/Process.py +++ b/pywps/app/Process.py @@ -201,7 +201,7 @@ def _execute_process(self, async_, wps_request, wps_response): LOGGER.debug("Stored processes: {}".format(stored)) if running < maxparallel or maxparallel == -1: - wps_response._update_status(WPS_STATUS.ACCEPTED, u"PyWPS Request accepted", 0) + wps_response._update_status(WPS_STATUS.ACCEPTED, "PyWPS Request accepted", 0) LOGGER.debug("Accepted request {}".format(self.uuid)) self._run_async(wps_request, wps_response) @@ -212,13 +212,13 @@ def _execute_process(self, async_, wps_request, wps_response): raise ServerBusy('Maximum number of processes in queue reached. Please try later.') LOGGER.debug("Store process in job queue, uuid={}".format(self.uuid)) dblog.store_process(self.uuid, wps_request) - wps_response._update_status(WPS_STATUS.ACCEPTED, u'PyWPS Process stored in job queue', 0) + wps_response._update_status(WPS_STATUS.ACCEPTED, 'PyWPS Process stored in job queue', 0) # not async else: if running >= maxparallel and maxparallel != -1: raise ServerBusy('Maximum number of parallel running processes reached. Please try later.') - wps_response._update_status(WPS_STATUS.ACCEPTED, u"PyWPS Request accepted", 0) + wps_response._update_status(WPS_STATUS.ACCEPTED, "PyWPS Request accepted", 0) wps_response = self._run_process(wps_request, wps_response) return wps_response @@ -245,7 +245,7 @@ def _run_process(self, wps_request, wps_response): os.environ['HOME'] = self.workdir LOGGER.info('Setting HOME to current working directory: {}'.format(os.environ['HOME'])) LOGGER.debug('ProcessID={}, HOME={}'.format(self.uuid, os.environ.get('HOME'))) - wps_response._update_status(WPS_STATUS.STARTED, u'PyWPS Process started', 0) + wps_response._update_status(WPS_STATUS.STARTED, 'PyWPS Process started', 0) self.handler(wps_request, wps_response) # the user must update the wps_response. # Ensure process termination if wps_response.status != WPS_STATUS.SUCCEEDED and wps_response.status != WPS_STATUS.FAILED: diff --git a/pywps/app/Service.py b/pywps/app/Service.py index 003a9a313..045e1a8f6 100755 --- a/pywps/app/Service.py +++ b/pywps/app/Service.py @@ -7,8 +7,7 @@ import tempfile from werkzeug.exceptions import HTTPException from werkzeug.wrappers import Request, Response -from pywps._compat import PY2 -from pywps._compat import urlparse +from urllib.parse import urlparse from pywps.app.WPSRequest import WPSRequest import pywps.configuration as config from pywps.exceptions import MissingParameterValue, NoApplicableCode, InvalidParameterValue, FileSizeExceeded, \ @@ -318,11 +317,11 @@ def call(self, http_request): response = None if wps_request.operation == 'getcapabilities': response = self.get_capabilities(wps_request, request_uuid) - response._update_status(WPS_STATUS.SUCCEEDED, u'', 100) + response._update_status(WPS_STATUS.SUCCEEDED, '', 100) elif wps_request.operation == 'describeprocess': response = self.describe(wps_request, request_uuid, wps_request.identifiers) - response._update_status(WPS_STATUS.SUCCEEDED, u'', 100) + response._update_status(WPS_STATUS.SUCCEEDED, '', 100) elif wps_request.operation == 'execute': response = self.execute( @@ -334,7 +333,7 @@ def call(self, http_request): except Exception as e: # This ensure that logged request get terminated in case of exception while the request is not # accepted - store_status(request_uuid, WPS_STATUS.FAILED, u'Request rejected due to exception', 100) + store_status(request_uuid, WPS_STATUS.FAILED, 'Request rejected due to exception', 100) raise e else: raise RuntimeError("Unknown operation {}".format(wps_request.operation)) diff --git a/pywps/app/WPSRequest.py b/pywps/app/WPSRequest.py index 2712e7565..f39a87973 100644 --- a/pywps/app/WPSRequest.py +++ b/pywps/app/WPSRequest.py @@ -10,7 +10,6 @@ from pywps import get_ElementMakerForVersion import base64 import datetime -from pywps._compat import text_type, PY2 from pywps.app.basic import get_xpath_ns from pywps.inout.inputs import input_from_json from pywps.exceptions import NoApplicableCode, OperationNotSupported, MissingParameterValue, VersionNegotiationFailed, \ @@ -87,10 +86,7 @@ def _post_request(self): try: doc = lxml.etree.fromstring(self.http_request.get_data()) except Exception as e: - if PY2: - raise NoApplicableCode(e.message) - else: - raise NoApplicableCode(e.msg) + raise NoApplicableCode(e.msg) operation = doc.tag version = get_version_from_ns(doc.nsmap[doc.prefix]) @@ -191,7 +187,7 @@ def parse_post_getcapabilities(doc): acceptedversions = self.xpath_ns( doc, '/wps:GetCapabilities/ows:AcceptVersions/ows:Version') acceptedversions = ','.join( - map(lambda v: v.text, acceptedversions)) + [v.text for v in acceptedversions]) wpsrequest.check_accepted_versions(acceptedversions) language = doc.attrib.get('language') @@ -395,7 +391,7 @@ def get_inputs_from_xml(doc): value_el = literal_data[0] inpt = {} inpt['identifier'] = identifier_el.text - inpt['data'] = text_type(value_el.text) + inpt['data'] = str(value_el.text) inpt['uom'] = value_el.attrib.get('uom', '') inpt['datatype'] = value_el.attrib.get('datatype', '') the_inputs[identifier].append(inpt) @@ -574,10 +570,7 @@ def _get_dataelement_value(value_el): """ if isinstance(value_el, lxml.etree._Element): - if PY2: - return lxml.etree.tostring(value_el, encoding=unicode) # noqa - else: - return lxml.etree.tostring(value_el, encoding=str) + return lxml.etree.tostring(value_el, encoding=str) else: return value_el diff --git a/pywps/exceptions.py b/pywps/exceptions.py index 30b3e6bbf..6382fe832 100644 --- a/pywps/exceptions.py +++ b/pywps/exceptions.py @@ -14,7 +14,6 @@ from werkzeug.wrappers import Response from werkzeug.exceptions import HTTPException -from werkzeug._compat import text_type from werkzeug.utils import escape import logging @@ -66,14 +65,14 @@ def get_response(self, environ=None): 'name': escape(self.name), 'description': self.get_description(environ) } - doc = text_type(( - u'\n' - u'\n' - u'\n' # noqa - u' \n' - u' {description}\n' - u' \n' - u'' + doc = str(( + '\n' + '\n' + '\n' # noqa + ' \n' + ' {description}\n' + ' \n' + '' ).format(**args)) return Response(doc, self.code, mimetype='text/xml') @@ -134,13 +133,13 @@ def get_body(self, environ=None): 'name': escape(self.name), 'description': self.get_description(environ) } - return text_type(( - u'\n' - u'' # noqa - u'' - u'{description}' - u'' - u'' + return str(( + '\n' + '' # noqa + '' + '{description}' + '' + '' ).format(**args)) diff --git a/pywps/ext_autodoc.py b/pywps/ext_autodoc.py index 082b16e29..bb8728ea2 100644 --- a/pywps/ext_autodoc.py +++ b/pywps/ext_autodoc.py @@ -36,8 +36,7 @@ class ProcessDocumenter(ClassDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): - from six import class_types - return isinstance(member, class_types) and issubclass(member, Process) + return isinstance(member, type) and issubclass(member, Process) def fmt_type(self, obj): """Input and output type formatting (type, default and allowed @@ -90,7 +89,7 @@ class instance. # Description doc = list() - doc.append(u":program:`{}` {} (v{})".format(obj.identifier, obj.title, obj.version or '', )) + doc.append(":program:`{}` {} (v{})".format(obj.identifier, obj.title, obj.version or '', )) doc.append('') doc.append(obj.abstract) doc.append('') @@ -130,7 +129,7 @@ class instance. if isinstance(m, MetadataUrl): extra_underscore = "_" if m.anonymous else "" if title and href: - ref.append(u" - `{} <{}>`_{}".format(title, href, extra_underscore)) + ref.append(" - `{} <{}>`_{}".format(title, href, extra_underscore)) hasref = True ref.append('') @@ -144,16 +143,13 @@ def get_doc(self, encoding=None, ignore=1): """Overrides ClassDocumenter.get_doc to create the doc scraped from the Process object, then adds additional content from the class docstring. """ - from six import text_type # Get the class docstring. This is a copy of the ClassDocumenter.get_doc method. Using "super" does weird stuff. docstring = self.get_attr(self.object, '__doc__', None) # make sure we have Unicode docstrings, then sanitize and split # into lines - if isinstance(docstring, text_type): + if isinstance(docstring, str): docstring = prepare_docstring(docstring, ignore) - elif isinstance(docstring, str): # this will not trigger on Py3 - docstring = prepare_docstring(force_decode(docstring, encoding), ignore) # Create the docstring by scraping info from the Process instance. pdocstrings = self.make_numpy_doc() diff --git a/pywps/inout/basic.py b/pywps/inout/basic.py index 1fa0c1d3b..ce0c3a9ea 100644 --- a/pywps/inout/basic.py +++ b/pywps/inout/basic.py @@ -4,7 +4,7 @@ ################################################################## from pywps.translations import lower_case_dict -from pywps._compat import text_type, StringIO +from io import StringIO import os from io import open import shutil @@ -25,7 +25,7 @@ validate_values_reference) from pywps.exceptions import NoApplicableCode, InvalidParameterValue, FileSizeExceeded, \ FileURLNotSupported -from pywps._compat import PY2, urlparse +from urllib.parse import urlparse import base64 from collections import namedtuple from copy import deepcopy @@ -334,21 +334,20 @@ def url(self): def _openmode(self, data=None): openmode = 'r' - if not PY2: - # in Python 3 we need to open binary files in binary mode. - checked = False - if hasattr(self, 'data_format'): - if self.data_format.encoding == 'base64': - # binary, when the data is to be encoded to base64 - openmode += 'b' - checked = True - elif 'text/' in self.data_format.mime_type: - # not binary, when mime_type is 'text/' - checked = True - # when we can't guess it from the mime_type, we need to check the file. - # mimetypes like application/xml and application/json are text files too. - if not checked and not _is_textfile(self.file): + # in Python 3 we need to open binary files in binary mode. + checked = False + if hasattr(self, 'data_format'): + if self.data_format.encoding == 'base64': + # binary, when the data is to be encoded to base64 openmode += 'b' + checked = True + elif 'text/' in self.data_format.mime_type: + # not binary, when mime_type is 'text/' + checked = True + # when we can't guess it from the mime_type, we need to check the file. + # mimetypes like application/xml and application/json are text files too. + if not checked and not _is_textfile(self.file): + openmode += 'b' return openmode @@ -357,7 +356,7 @@ class DataHandler(FileHandler): def _openmode(self, data=None): openmode = 'w' - if not PY2 and isinstance(data, bytes): + if isinstance(data, bytes): # on Python 3 open the file in binary mode if the source is # bytes, which happens when the data was base64-decoded openmode += 'b' @@ -392,10 +391,10 @@ def file(self): @property def stream(self): """Return a stream representation of the data.""" - if not PY2 and isinstance(self.data, bytes): + if isinstance(self.data, bytes): return BytesIO(self.data) else: - return StringIO(text_type(self.data)) + return StringIO(str(self.data)) class StreamHandler(DataHandler): diff --git a/pywps/inout/inputs.py b/pywps/inout/inputs.py index 0fa3a5c08..4c724ee31 100644 --- a/pywps/inout/inputs.py +++ b/pywps/inout/inputs.py @@ -5,7 +5,6 @@ import re import lxml.etree as etree -import six from pywps.app.Common import Metadata from pywps.exceptions import InvalidParameterValue @@ -248,7 +247,7 @@ def _json_data(self, data): else: out = self.data - data["data"] = u''.format(out) + data["data"] = ''.format(out) return data diff --git a/pywps/inout/literaltypes.py b/pywps/inout/literaltypes.py index 729defc16..8a93a246c 100644 --- a/pywps/inout/literaltypes.py +++ b/pywps/inout/literaltypes.py @@ -6,13 +6,12 @@ """Literaltypes are used for LiteralInputs, to make sure, input data are OK """ -from pywps._compat import urlparse +from urllib.parse import urlparse from dateutil.parser import parse as date_parser import datetime from pywps.exceptions import InvalidParameterValue from pywps.validator.allowed_value import RANGECLOSURETYPE from pywps.validator.allowed_value import ALLOWEDVALUETYPE -from pywps._compat import PY2 import logging LOGGER = logging.getLogger('PYWPS') @@ -281,11 +280,7 @@ def convert_string(inpt): >>> convert_string(1) '1' """ - - if PY2: - return str(inpt).decode() - else: - return str(inpt) + return str(inpt) def convert_positiveInteger(inpt): diff --git a/pywps/inout/outputs.py b/pywps/inout/outputs.py index e52b30206..9c0a663da 100644 --- a/pywps/inout/outputs.py +++ b/pywps/inout/outputs.py @@ -230,7 +230,7 @@ def _json_data(self, data): else: out = self.data - data["data"] = u''.format(out) + data["data"] = ''.format(out) return data diff --git a/pywps/inout/storage/__init__.py b/pywps/inout/storage/__init__.py index 9c4ecd10c..2931a83f7 100644 --- a/pywps/inout/storage/__init__.py +++ b/pywps/inout/storage/__init__.py @@ -16,12 +16,10 @@ class STORE_TYPE: # TODO: cover with tests -class StorageAbstract(object): +class StorageAbstract(object, metaclass=ABCMeta): """Data storage abstract class """ - __metaclass__ = ABCMeta - @abstractmethod def store(self, output): """ diff --git a/pywps/inout/storage/file.py b/pywps/inout/storage/file.py index 77e0081ce..528debf8c 100644 --- a/pywps/inout/storage/file.py +++ b/pywps/inout/storage/file.py @@ -5,7 +5,7 @@ import logging import os -from pywps._compat import urljoin +from urllib.parse import urljoin from pywps.exceptions import NotEnoughStorage from pywps import configuration as config from pywps.inout.basic import IOHandler diff --git a/pywps/inout/storage/implementationbuilder.py b/pywps/inout/storage/implementationbuilder.py index 6fd97d53d..271858830 100644 --- a/pywps/inout/storage/implementationbuilder.py +++ b/pywps/inout/storage/implementationbuilder.py @@ -6,15 +6,13 @@ from abc import ABCMeta, abstractmethod -class StorageImplementationBuilder(object): +class StorageImplementationBuilder(object, metaclass=ABCMeta): """ Storage implementations should implement this class and build method then import and register the build class into the StorageBuilder. """ - __metaclass__ = ABCMeta - @abstractmethod def build(self): """ diff --git a/pywps/response/__init__.py b/pywps/response/__init__.py index f31e50e40..d20122b08 100644 --- a/pywps/response/__init__.py +++ b/pywps/response/__init__.py @@ -69,6 +69,6 @@ def get_response_doc(self): raise e else: - self._update_status(WPS_STATUS.SUCCEEDED, u"Response generated", 100) + self._update_status(WPS_STATUS.SUCCEEDED, "Response generated", 100) return self.doc diff --git a/pywps/response/execute.py b/pywps/response/execute.py index 15a6b1425..e96b044c7 100755 --- a/pywps/response/execute.py +++ b/pywps/response/execute.py @@ -15,14 +15,8 @@ from pywps.response import WPSResponse from pywps.inout.formats import FORMATS -from pywps._compat import PY2 - -if PY2: - import urlparse - from urllib import urlencode -else: - import urllib.parse as urlparse - from urllib.parse import urlencode +import urllib.parse as urlparse +from urllib.parse import urlencode LOGGER = logging.getLogger("PYWPS") diff --git a/pywps/validator/complexvalidator.py b/pywps/validator/complexvalidator.py index 42ebf43f5..a1fc73750 100644 --- a/pywps/validator/complexvalidator.py +++ b/pywps/validator/complexvalidator.py @@ -11,6 +11,7 @@ from pywps.validator.mode import MODE from pywps.inout.formats import FORMATS +from urllib.request import urlopen import mimetypes import os diff --git a/pywps/wpsserver.py b/pywps/wpsserver.py index e4b4a6ecf..6ffe762ea 100755 --- a/pywps/wpsserver.py +++ b/pywps/wpsserver.py @@ -23,12 +23,10 @@ def temp_dir(): shutil.rmtree(tmp) -class PyWPSServerAbstract(object): +class PyWPSServerAbstract(object, metaclass=ABCMeta): """General stub for the PyWPS Server class. """ - __metaclass__ = ABCMeta - route_base = '/' @abstractmethod diff --git a/requirements-dev.txt b/requirements-dev.txt index c9b96c8f7..526762a44 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,7 +2,6 @@ coverage coveralls flake8 pylint -six Sphinx twine wheel diff --git a/tests/test_execute.py b/tests/test_execute.py index 0e4afb37f..3763ea7e1 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -17,14 +17,11 @@ from pywps import get_inputs_from_xml, get_output_from_xml from pywps import E, get_ElementMakerForVersion from pywps.app.basic import get_xpath_ns -from pywps._compat import text_type from pywps.tests import client_for, assert_response_success from pywps import configuration -from pywps._compat import PY2 -from pywps._compat import StringIO -if PY2: - from owslib.ows import BoundingBox +from io import StringIO +from owslib.ows import BoundingBox try: import netCDF4 @@ -56,7 +53,7 @@ def handler(request, response): def create_greeter(): def greeter(request, response): name = request.inputs['name'][0].data - assert type(name) is text_type + assert isinstance(name, str) response.outputs['message'].data = "Hello {}!".format(name) return response @@ -234,8 +231,6 @@ class ExecuteTest(unittest.TestCase): """Test for Exeucte request KVP request""" def test_dods(self): - if PY2: - self.skipTest('fails on python 2.7') if not WITH_NC4: self.skipTest('netCDF4 not installed') my_process = create_complex_nc_process() @@ -282,7 +277,7 @@ class FakeRequest(): request = FakeRequest() resp = service.execute('my_opendap_process', request, 'fakeuuid') - self.assertEqual(resp.outputs['conventions'].data, u'CF-1.0') + self.assertEqual(resp.outputs['conventions'].data, 'CF-1.0') self.assertEqual(resp.outputs['outdods'].url, href) self.assertTrue(resp.outputs['outdods'].as_reference) self.assertFalse(resp.outputs['ncraw'].as_reference) @@ -295,7 +290,7 @@ def test_input_parser(self): """ my_process = create_complex_proces() service = Service(processes=[my_process]) - self.assertEqual(len(service.processes.keys()), 1) + self.assertEqual(len(service.processes), 1) self.assertTrue(service.processes['my_complex_process']) class FakeRequest(): @@ -352,7 +347,7 @@ def test_input_default(self): """ my_process = create_complex_proces() service = Service(processes=[my_process]) - self.assertEqual(len(service.processes.keys()), 1) + self.assertEqual(len(service.processes), 1) self.assertTrue(service.processes['my_complex_process']) class FakeRequest(): @@ -376,7 +371,7 @@ def test_output_mimetype(self): """ my_process = create_mimetype_process() service = Service(processes=[my_process]) - self.assertEqual(len(service.processes.keys()), 1) + self.assertEqual(len(service.processes), 1) self.assertTrue(service.processes['get_mimetype_process']) class FakeRequest(): @@ -640,8 +635,6 @@ def test_complex_input_base64_value(self): self.assertEqual(json_data['plot']['Version'], '0.1') def test_bbox_input(self): - if not PY2: - self.skipTest('OWSlib not python 3 compatible') request_doc = WPS.Execute( OWS.Identifier('request'), WPS.DataInputs( diff --git a/tests/test_filestorage.py b/tests/test_filestorage.py index 6c768f246..28d970662 100644 --- a/tests/test_filestorage.py +++ b/tests/test_filestorage.py @@ -8,7 +8,7 @@ from pywps.inout.basic import ComplexOutput from pywps import configuration, FORMATS -from pywps._compat import urlparse +from urllib.parse import urlparse import tempfile import os diff --git a/tests/test_inout.py b/tests/test_inout.py index ab436d711..26963ed8a 100644 --- a/tests/test_inout.py +++ b/tests/test_inout.py @@ -7,7 +7,7 @@ # licensed under MIT, Please consult LICENSE.txt for details # ################################################################## -from __future__ import absolute_import + import requests import os import tempfile @@ -24,12 +24,12 @@ ComplexInput, ComplexOutput, LiteralOutput, LiteralInput, _is_textfile from pywps.inout.literaltypes import convert, AllowedValue, AnyValue from pywps.inout.outputs import MetaFile, MetaLink, MetaLink4 -from pywps._compat import StringIO, text_type, urlparse +from io import StringIO +from urllib.parse import urlparse from pywps.validator.base import emptyvalidator from pywps.exceptions import InvalidParameterValue from pywps.validator.mode import MODE from pywps.inout.basic import UOM -from pywps._compat import PY2 from pywps.inout.storage.file import FileStorageBuilder from pywps.tests import service_ok from pywps.translations import get_translation @@ -77,7 +77,7 @@ def _test_outout(self, source_type, suffix=''): self.assertEqual('file', urlparse(self.iohandler.url).scheme) if self.iohandler.source_type == SOURCE_TYPE.STREAM: - source = StringIO(text_type(self._value)) + source = StringIO(str(self._value)) self.iohandler.stream = source file_path = self.iohandler.file @@ -87,16 +87,13 @@ def _test_outout(self, source_type, suffix=''): file_handler.close() if self.iohandler.source_type == SOURCE_TYPE.STREAM: - source = StringIO(text_type(self._value)) + source = StringIO(str(self._value)) self.iohandler.stream = source stream_val = self.iohandler.stream.read() self.iohandler.stream.close() - if PY2 and isinstance(stream_val, str): - self.assertEqual(self._value, stream_val.decode('utf-8'), - 'Stream obtained') - elif not PY2 and isinstance(stream_val, bytes): + if isinstance(stream_val, bytes): self.assertEqual(self._value, stream_val.decode('utf-8'), 'Stream obtained') else: @@ -104,7 +101,7 @@ def _test_outout(self, source_type, suffix=''): 'Stream obtained') if self.iohandler.source_type == SOURCE_TYPE.STREAM: - source = StringIO(text_type(self._value)) + source = StringIO(str(self._value)) self.iohandler.stream = source # self.assertEqual(stream_val, self.iohandler.memory_object, @@ -112,15 +109,13 @@ def _test_outout(self, source_type, suffix=''): def test_data(self): """Test data input IOHandler""" - if PY2: - self.skipTest('fails on python 2.7') self.iohandler.data = self._value self.iohandler.data_format = Format('foo', extension='.foo') self._test_outout(SOURCE_TYPE.DATA, '.foo') def test_stream(self): """Test stream input IOHandler""" - source = StringIO(text_type(self._value)) + source = StringIO(str(self._value)) self.iohandler.stream = source self._test_outout(SOURCE_TYPE.STREAM) @@ -163,8 +158,6 @@ def test_memory(self): self.skipTest('Memory object not implemented') def test_data_bytes(self): - if PY2: - self.skipTest('fails on python 2.7') self._value = b'aa' self.iohandler.data = self._value @@ -468,7 +461,7 @@ def setUp(self): supported_formats=[data_format], mode=MODE.NONE, translations={"fr-CA": {"title": "Mon output", "abstract": "Une description"}}, - ) + ) self.complex_out_nc = inout.outputs.ComplexOutput( identifier="netcdf", @@ -478,7 +471,7 @@ def setUp(self): supported_formats=[get_data_format('application/x-netcdf')], mode=MODE.NONE) - self.data = json.dumps({'a': 1, 'unicodé': u'éîïç', }) + self.data = json.dumps({'a': 1, 'unicodé': 'éîïç', }) self.ncfile = os.path.join(DATA_DIR, 'netcdf', 'time.nc') self.test_fn = os.path.join(self.complex_out.workdir, 'test.json') @@ -508,24 +501,17 @@ def test_validator(self): def test_file_handler(self): self.complex_out.file = self.test_fn self.assertEqual(self.complex_out.data, self.data) - if PY2: - self.assertEqual(self.complex_out.stream.read(), self.data) - else: - with self.complex_out.stream as s: - self.assertEqual(s.read(), bytes(self.data, encoding='utf8')) + with self.complex_out.stream as s: + self.assertEqual(s.read(), bytes(self.data, encoding='utf8')) with open(urlparse(self.complex_out.url).path) as f: self.assertEqual(f.read(), self.data) def test_file_handler_netcdf(self): - if PY2: - self.skipTest('fails on python 2.7') self.complex_out_nc.file = self.ncfile self.complex_out_nc.base64 def test_data_handler(self): - if PY2: - self.skipTest('fails on python 2.7') self.complex_out.data = self.data with open(self.complex_out.file) as f: self.assertEqual(f.read(), self.data) @@ -533,10 +519,7 @@ def test_data_handler(self): def test_base64(self): self.complex_out.data = self.data b = self.complex_out.base64 - if PY2: - self.assertEqual(base64.b64decode(b), self.data) - else: - self.assertEqual(base64.b64decode(b).decode(), self.data) + self.assertEqual(base64.b64decode(b).decode(), self.data) def test_url_handler(self): wfsResource = 'http://demo.mapserver.org/cgi-bin/wfs?' \ @@ -677,6 +660,7 @@ def test_translations(self): identifier = get_translation(self.literal_input, "identifier", "fr-CA") assert identifier == self.literal_input.identifier + class LiteralOutputTest(unittest.TestCase): """LiteralOutput test cases""" diff --git a/tests/test_s3storage.py b/tests/test_s3storage.py index 964fc4805..e2708c9b3 100644 --- a/tests/test_s3storage.py +++ b/tests/test_s3storage.py @@ -8,23 +8,20 @@ from pywps.inout.basic import ComplexOutput from pywps import configuration, FORMATS -from pywps._compat import urlparse, PY2 +from urllib.parse import urlparse import tempfile import os import unittest -if PY2: - from mock import patch -else: - from unittest.mock import patch +from unittest.mock import patch + class S3StorageTests(unittest.TestCase): def setUp(self): self.tmp_dir = tempfile.mkdtemp() - @patch('pywps.inout.storage.s3.S3Storage.uploadData') def test_store(self, uploadData): configuration.CONFIG.set('s3', 'bucket', 'notrealbucket') @@ -68,4 +65,4 @@ def load_tests(loader=None, tests=None, pattern=None): suite_list = [ loader.loadTestsFromTestCase(S3StorageTests) ] - return unittest.TestSuite(suite_list) \ No newline at end of file + return unittest.TestSuite(suite_list) diff --git a/tox.ini b/tox.ini index f8dbaa1d8..8bdfbe5fe 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,6 @@ [tox] envlist=py27,py36 -[testenv:py27] -deps = flufl.enum - jinja2 - mock - [testenv] pip_pre=True From 89dbb5881642ab1cebd6d73f4d0314506221050d Mon Sep 17 00:00:00 2001 From: Pingu Carsti Date: Thu, 13 Feb 2020 15:10:12 +0100 Subject: [PATCH 04/16] removed unused wpsserver.py --- pywps/inout/basic.py | 9 -------- pywps/validator/complexvalidator.py | 10 --------- pywps/wpsserver.py | 34 ----------------------------- tests/test_ows.py | 1 - 4 files changed, 54 deletions(-) delete mode 100755 pywps/wpsserver.py diff --git a/pywps/inout/basic.py b/pywps/inout/basic.py index ce0c3a9ea..833b5201e 100644 --- a/pywps/inout/basic.py +++ b/pywps/inout/basic.py @@ -1006,12 +1006,3 @@ def get_url(self): (_, _, url) = self.storage.store(self) # url = self.storage.url(self) return url - - -if __name__ == "__main__": - import doctest - from pywps.wpsserver import temp_dir - - with temp_dir() as tmp: - os.chdir(tmp) - doctest.testmod() diff --git a/pywps/validator/complexvalidator.py b/pywps/validator/complexvalidator.py index a1fc73750..7ed8ec5a3 100644 --- a/pywps/validator/complexvalidator.py +++ b/pywps/validator/complexvalidator.py @@ -451,13 +451,3 @@ def _get_schemas_home(): "schemas") LOGGER.debug('Schemas directory: {}'.format(schema_dir)) return schema_dir - - -if __name__ == "__main__": - import doctest - - from pywps.wpsserver import temp_dir - - with temp_dir() as tmp: - os.chdir(tmp) - doctest.testmod() diff --git a/pywps/wpsserver.py b/pywps/wpsserver.py deleted file mode 100755 index 6ffe762ea..000000000 --- a/pywps/wpsserver.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Abstract Server class -""" - -################################################################## -# Copyright 2018 Open Source Geospatial Foundation and others # -# licensed under MIT, Please consult LICENSE.txt for details # -################################################################## - -from abc import abstractmethod, ABCMeta -from contextlib import contextmanager -import shutil -import tempfile - - -@contextmanager -def temp_dir(): - """Creates temporary directory""" - tmp = tempfile.mkdtemp() - try: - yield tmp - finally: - shutil.rmtree(tmp) - - -class PyWPSServerAbstract(object, metaclass=ABCMeta): - """General stub for the PyWPS Server class. - """ - - route_base = '/' - - @abstractmethod - def run(self): - raise NotImplementedError() diff --git a/tests/test_ows.py b/tests/test_ows.py index 75338313c..d35d2f11a 100644 --- a/tests/test_ows.py +++ b/tests/test_ows.py @@ -15,7 +15,6 @@ from pywps.dependencies import ogr from pywps.exceptions import NoApplicableCode from pywps import get_ElementMakerForVersion -from pywps.wpsserver import temp_dir import pywps.configuration as config from pywps.tests import client_for, assert_response_success, service_ok From 2b5662ef05864fd1ca18271d0e92a1119d5142ed Mon Sep 17 00:00:00 2001 From: David Caron Date: Mon, 24 Feb 2020 13:35:56 -0500 Subject: [PATCH 05/16] allow custom UOM reference for literal IO --- pywps/inout/basic.py | 8 ++++++-- pywps/inout/inputs.py | 7 +++++-- pywps/inout/outputs.py | 7 +++++-- tests/test_inout.py | 11 ++++++++--- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/pywps/inout/basic.py b/pywps/inout/basic.py index 833b5201e..c4162cc5f 100644 --- a/pywps/inout/basic.py +++ b/pywps/inout/basic.py @@ -65,12 +65,16 @@ class UOM(object): :param uom: unit of measure """ - def __init__(self, uom=''): + def __init__(self, uom='', reference=None): self.uom = uom + self.reference = reference + + if self.reference is None: + self.reference = OGCUNIT[self.uom] @property def json(self): - return {"reference": OGCUNIT[self.uom], + return {"reference": self.reference, "uom": self.uom} def __eq__(self, other): diff --git a/pywps/inout/inputs.py b/pywps/inout/inputs.py index 4c724ee31..180fbf204 100644 --- a/pywps/inout/inputs.py +++ b/pywps/inout/inputs.py @@ -343,7 +343,10 @@ def from_json(cls, json_input): json_input_copy = deepcopy(json_input) json_input_copy['allowed_values'] = allowed_values - json_input_copy['uoms'] = [basic.UOM(uom.get('uom')) for uom in json_input.get('uoms', [])] + json_input_copy['uoms'] = [ + basic.UOM(uom['uom'], uom['reference']) + for uom in json_input.get('uoms', []) + ] data = json_input_copy.pop('data', None) uom = json_input_copy.pop('uom', None) @@ -357,7 +360,7 @@ def from_json(cls, json_input): instance.metadata = [Metadata.from_json(d) for d in metadata] instance.data = data if uom: - instance.uom = basic.UOM(uom['uom']) + instance.uom = basic.UOM(uom['uom'], uom['reference']) return instance diff --git a/pywps/inout/outputs.py b/pywps/inout/outputs.py index 9c0a663da..c9238c4d9 100644 --- a/pywps/inout/outputs.py +++ b/pywps/inout/outputs.py @@ -281,7 +281,10 @@ def json(self): @classmethod def from_json(cls, json_output): - uoms = [basic.UOM(uom.get('uom')) for uom in json_output.get('uoms', [])] + uoms = [ + basic.UOM(uom['uom'], uom['reference']) + for uom in json_output.get('uoms', []) + ] uom = json_output.get('uom') instance = cls( @@ -296,7 +299,7 @@ def from_json(cls, json_output): instance.data = json_output.get('data') if uom: - instance.uom = basic.UOM(uom['uom']) + instance.uom = basic.UOM(uom['uom'], uom['reference']) return instance diff --git a/tests/test_inout.py b/tests/test_inout.py index 26963ed8a..86e880cb0 100644 --- a/tests/test_inout.py +++ b/tests/test_inout.py @@ -569,7 +569,7 @@ def setUp(self): mode=2, allowed_values=(1, 2, (3, 3, 12)), default=6, - uoms=(UOM("metre"),), + uoms=(UOM("metre"), UOM("km / h", "custom reference")), translations={"fr-CA": {"title": "Mon input", "abstract": "Une description"}}, ) @@ -603,8 +603,10 @@ def test_json_out(self): self.literal_input.data = 9 out = self.literal_input.json - self.assertTrue('uoms' in out, 'UOMs does not exist') - self.assertTrue('uom' in out, 'uom does not exist') + self.assertEqual(out['uoms'][0]["uom"], "metre") + self.assertEqual(out['uoms'][1]["uom"], "km / h") + self.assertEqual(out['uoms'][1]["reference"], "custom reference") + self.assertEqual(out['uom']["uom"], "metre") self.assertFalse(out['workdir'], 'Workdir exist') self.assertEqual(out['data_type'], 'integer', 'Data type is integer') self.assertFalse(out['abstract'], 'abstract exist') @@ -670,6 +672,7 @@ def setUp(self): "literaloutput", data_type="integer", title="Literal Output", + uoms=[UOM("km / h", "custom reference"), UOM("m / s", "other reference")], translations={"fr-CA": {"title": "Mon output", "abstract": "Une description"}}, ) @@ -686,6 +689,8 @@ class Storage(object): def test_json(self): new_output = inout.outputs.LiteralOutput.from_json(self.literal_output.json) self.assertEqual(new_output.identifier, 'literaloutput') + self.assertEqual(new_output.uom, self.literal_output.uom) + self.assertEqual(new_output.uoms, self.literal_output.uoms) self.assertEqual( new_output.translations, {"fr-ca": {"title": "Mon output", "abstract": "Une description"}}, From cbd9b08001cb99299b3f6eeff695cf6131d56700 Mon Sep 17 00:00:00 2001 From: Trevor James Smith <10819524+Zeitsperre@users.noreply.github.com> Date: Tue, 24 Mar 2020 06:43:52 -0400 Subject: [PATCH 06/16] Use bump2version to track version changes (#527) * Set up bump2version --- requirements-dev.txt | 1 + setup.cfg | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 526762a44..fbb4201b9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,3 +5,4 @@ pylint Sphinx twine wheel +bump2version \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 2141c28a4..e50dd75fa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,20 @@ [flake8] ignore=F401,E402,W606 max-line-length=120 -exclude=tests +exclude=tests, pywps/alembic/versions + +[bumpversion] +current_version = 4.2.11 +commit = False +tag = False +parse = (?P\d+)\.(?P\d+).(?P\d+) +serialize = + {major}.{minor}.{patch} + +[bumpversion:file:pywps/__init__.py] +search = __version__ = "{current_version}" +replace = __version__ = "{new_version}" + +[bumpversion:file:VERSION.txt] +search = {current_version} +replace = {new_version} From 337ae8475f90cf50f61ae5b17fe9c469e683c1f7 Mon Sep 17 00:00:00 2001 From: David Huard Date: Wed, 25 Mar 2020 13:40:07 -0400 Subject: [PATCH 07/16] fix: changed geojson mimetype. previous value was obsolete. --- pywps/inout/formats/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pywps/inout/formats/__init__.py b/pywps/inout/formats/__init__.py index de86d3b22..7692c8aee 100644 --- a/pywps/inout/formats/__init__.py +++ b/pywps/inout/formats/__init__.py @@ -163,7 +163,7 @@ def json(self, jsonin): FORMATS = _FORMATS( - Format('application/vnd.geo+json', extension='.geojson'), + Format('application/geo+json', extension='.geojson'), Format('application/json', extension='.json'), Format('application/x-zipped-shp', extension='.zip', encoding='base64'), Format('application/gml+xml', extension='.gml'), From d04c77d07ee6a4151ac0fd723ad452c7a3a2dd59 Mon Sep 17 00:00:00 2001 From: Jachym Cepicky Date: Thu, 9 Jul 2020 15:50:17 +0200 Subject: [PATCH 08/16] adding plural to units --- pywps/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pywps/__init__.py b/pywps/__init__.py index a53fd86d9..79887a863 100644 --- a/pywps/__init__.py +++ b/pywps/__init__.py @@ -79,7 +79,9 @@ def get_version_from_ns(ns): OGCUNIT = { 'degree': 'urn:ogc:def:uom:OGC:1.0:degree', + 'degrees': 'urn:ogc:def:uom:OGC:1.0:degree', 'metre': 'urn:ogc:def:uom:OGC:1.0:metre', + 'metres': 'urn:ogc:def:uom:OGC:1.0:metre', 'unity': 'urn:ogc:def:uom:OGC:1.0:unity' } From 768efd96aede467c676077cf152185670c765a76 Mon Sep 17 00:00:00 2001 From: Jachym Cepicky Date: Thu, 9 Jul 2020 16:17:52 +0200 Subject: [PATCH 09/16] typo --- pywps/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pywps/__init__.py b/pywps/__init__.py index 79887a863..aaccb9f7d 100644 --- a/pywps/__init__.py +++ b/pywps/__init__.py @@ -80,8 +80,8 @@ def get_version_from_ns(ns): OGCUNIT = { 'degree': 'urn:ogc:def:uom:OGC:1.0:degree', 'degrees': 'urn:ogc:def:uom:OGC:1.0:degree', - 'metre': 'urn:ogc:def:uom:OGC:1.0:metre', - 'metres': 'urn:ogc:def:uom:OGC:1.0:metre', + 'meter': 'urn:ogc:def:uom:OGC:1.0:metre', + 'meteres': 'urn:ogc:def:uom:OGC:1.0:metre', 'unity': 'urn:ogc:def:uom:OGC:1.0:unity' } From 4171583b5aae12282c509a6079a9a1e2e16bf882 Mon Sep 17 00:00:00 2001 From: Jachym Cepicky Date: Thu, 9 Jul 2020 16:34:10 +0200 Subject: [PATCH 10/16] another typo --- pywps/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pywps/__init__.py b/pywps/__init__.py index aaccb9f7d..47b9cfeee 100644 --- a/pywps/__init__.py +++ b/pywps/__init__.py @@ -82,6 +82,7 @@ def get_version_from_ns(ns): 'degrees': 'urn:ogc:def:uom:OGC:1.0:degree', 'meter': 'urn:ogc:def:uom:OGC:1.0:metre', 'meteres': 'urn:ogc:def:uom:OGC:1.0:metre', + 'meters': 'urn:ogc:def:uom:OGC:1.0:metre', 'unity': 'urn:ogc:def:uom:OGC:1.0:unity' } From ac3237419307625706ee457705c31e7d64ad519a Mon Sep 17 00:00:00 2001 From: Jachym Cepicky Date: Thu, 9 Jul 2020 16:37:55 +0200 Subject: [PATCH 11/16] adding feet --- pywps/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pywps/__init__.py b/pywps/__init__.py index 47b9cfeee..9c12abc61 100644 --- a/pywps/__init__.py +++ b/pywps/__init__.py @@ -83,7 +83,8 @@ def get_version_from_ns(ns): 'meter': 'urn:ogc:def:uom:OGC:1.0:metre', 'meteres': 'urn:ogc:def:uom:OGC:1.0:metre', 'meters': 'urn:ogc:def:uom:OGC:1.0:metre', - 'unity': 'urn:ogc:def:uom:OGC:1.0:unity' + 'unity': 'urn:ogc:def:uom:OGC:1.0:unity', + 'feet': 'urn:ogc:def:uom:OGC:1.0:feet' } from pywps.app import Process, Service, WPSRequest From 41a4997d3ee79f0953f3e6f1f9c859881ebaa570 Mon Sep 17 00:00:00 2001 From: Carsten Ehbrecht Date: Mon, 8 Feb 2021 18:12:53 +0100 Subject: [PATCH 12/16] removed PY2 --- pywps/app/Process.py | 4 +--- pywps/configuration.py | 11 ++--------- pywps/dblog.py | 6 ++---- pywps/validator/complexvalidator.py | 5 ----- 4 files changed, 5 insertions(+), 21 deletions(-) diff --git a/pywps/app/Process.py b/pywps/app/Process.py index 32790cee3..9dae0f3e2 100644 --- a/pywps/app/Process.py +++ b/pywps/app/Process.py @@ -19,7 +19,6 @@ from pywps.inout.inputs import input_from_json from pywps.inout.outputs import output_from_json import pywps.configuration as config -from pywps._compat import PY2 from pywps.exceptions import (StorageNotSupported, OperationNotSupported, ServerBusy, NoApplicableCode) from pywps.app.exceptions import ProcessError @@ -303,8 +302,7 @@ def launch_next_process(self): return (uuid, request_json) = (stored_request.uuid, stored_request.request) - if not PY2: - request_json = request_json.decode('utf-8') + request_json = request_json.decode('utf-8') LOGGER.debug("Launching the stored request {}".format(str(uuid))) new_wps_request = WPSRequest() new_wps_request.json = json.loads(request_json) diff --git a/pywps/configuration.py b/pywps/configuration.py index ff7ade193..a9336d4c3 100755 --- a/pywps/configuration.py +++ b/pywps/configuration.py @@ -13,11 +13,7 @@ import tempfile import pywps -from pywps._compat import PY2 -if PY2: - import ConfigParser -else: - import configparser +import configparser __author__ = "Calin Ciociu" @@ -67,10 +63,7 @@ def load_configuration(cfgfiles=None): global CONFIG LOGGER.info('loading configuration') - if PY2: - CONFIG = ConfigParser.SafeConfigParser(os.environ) - else: - CONFIG = configparser.ConfigParser(os.environ) + CONFIG = configparser.ConfigParser(os.environ) LOGGER.debug('setting default values') CONFIG.add_section('server') diff --git a/pywps/dblog.py b/pywps/dblog.py index 869532ee0..78e25e8d4 100644 --- a/pywps/dblog.py +++ b/pywps/dblog.py @@ -10,7 +10,6 @@ import logging from pywps import configuration from pywps.exceptions import NoApplicableCode -from pywps._compat import PY2 import sqlite3 import datetime import pickle @@ -191,9 +190,8 @@ def store_process(uuid, request): session = get_session() request_json = request.json - if not PY2: - # the BLOB type requires bytes on Python 3 - request_json = request_json.encode('utf-8') + # the BLOB type requires bytes on Python 3 + request_json = request_json.encode('utf-8') request = RequestInstance(uuid=str(uuid), request=request_json) session.add(request) session.commit() diff --git a/pywps/validator/complexvalidator.py b/pywps/validator/complexvalidator.py index 7ed8ec5a3..3695d2ab9 100644 --- a/pywps/validator/complexvalidator.py +++ b/pywps/validator/complexvalidator.py @@ -15,11 +15,6 @@ import mimetypes import os -from pywps._compat import PY2 -if PY2: - from urllib2 import urlopen -else: - from urllib.request import urlopen LOGGER = logging.getLogger('PYWPS') From ff61cc9d741917c77b05fda0041c0e1e31593151 Mon Sep 17 00:00:00 2001 From: Carsten Ehbrecht Date: Mon, 8 Feb 2021 18:19:56 +0100 Subject: [PATCH 13/16] add metre to UOMs --- pywps/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pywps/__init__.py b/pywps/__init__.py index 9c12abc61..3add8237e 100644 --- a/pywps/__init__.py +++ b/pywps/__init__.py @@ -81,6 +81,7 @@ def get_version_from_ns(ns): 'degree': 'urn:ogc:def:uom:OGC:1.0:degree', 'degrees': 'urn:ogc:def:uom:OGC:1.0:degree', 'meter': 'urn:ogc:def:uom:OGC:1.0:metre', + 'metre': 'urn:ogc:def:uom:OGC:1.0:metre', 'meteres': 'urn:ogc:def:uom:OGC:1.0:metre', 'meters': 'urn:ogc:def:uom:OGC:1.0:metre', 'unity': 'urn:ogc:def:uom:OGC:1.0:unity', From b5dda540c5a77953e5ee35a80a12da5a081c1eaa Mon Sep 17 00:00:00 2001 From: Carsten Ehbrecht Date: Mon, 8 Feb 2021 18:36:37 +0100 Subject: [PATCH 14/16] fixed bbox test --- tests/test_execute.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/test_execute.py b/tests/test_execute.py index 3763ea7e1..9eec7d98e 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -646,11 +646,12 @@ def test_bbox_input(self): OWS.UpperCorner('60 70')))))) rv = get_inputs_from_xml(request_doc) bbox = rv['bbox'][0] - assert isinstance(bbox, BoundingBox) - assert bbox.minx == '40' - assert bbox.miny == '50' - assert bbox.maxx == '60' - assert bbox.maxy == '70' + # assert isinstance(bbox, BoundingBox) + assert bbox['data'] == ['40', '50', '60', '70'] + # assert bbox.minx == '40' + # assert bbox.miny == '50' + # assert bbox.maxx == '60' + # assert bbox.maxy == '70' def test_reference_post_input(self): request_doc = WPS.Execute( From cafb028b7f4df09b3da0867f43d4f73d0dfacb29 Mon Sep 17 00:00:00 2001 From: Carsten Ehbrecht Date: Mon, 8 Feb 2021 19:21:19 +0100 Subject: [PATCH 15/16] remove py27 in tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 8bdfbe5fe..990d7b221 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27,py36 +envlist=py36 [testenv] From 4f15fc68d5c1e8166c242326dd47043eb178c805 Mon Sep 17 00:00:00 2001 From: Carsten Ehbrecht Date: Tue, 9 Feb 2021 15:18:51 +0100 Subject: [PATCH 16/16] use version 4.4.0 --- VERSION.txt | 2 +- pywps/__init__.py | 2 +- setup.cfg | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 7cac85078..fdc669880 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -4.2.11 +4.4.0 diff --git a/pywps/__init__.py b/pywps/__init__.py index 3add8237e..d0638a916 100644 --- a/pywps/__init__.py +++ b/pywps/__init__.py @@ -9,7 +9,7 @@ from lxml.builder import ElementMaker -__version__ = '4.2.11' +__version__ = '4.4.0' LOGGER = logging.getLogger('PYWPS') LOGGER.debug('setting core variables') diff --git a/setup.cfg b/setup.cfg index e50dd75fa..4b095fea0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,10 +1,10 @@ [flake8] ignore=F401,E402,W606 max-line-length=120 -exclude=tests, pywps/alembic/versions +exclude=tests [bumpversion] -current_version = 4.2.11 +current_version = 4.4.0 commit = False tag = False parse = (?P\d+)\.(?P\d+).(?P\d+)