-
Notifications
You must be signed in to change notification settings - Fork 5
/
wps.py
199 lines (168 loc) · 8.62 KB
/
wps.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
"""
pywps 4.x wrapper
"""
import logging
import os
import tempfile
from typing import TYPE_CHECKING
import six
from pyramid.settings import asbool
from pyramid.threadlocal import get_current_request
from pyramid.wsgi import wsgiapp2
from pyramid_celery import celery_app as app
from pywps import configuration as pywps_config
from pywps.app.Service import Service
from six.moves.configparser import ConfigParser
from six.moves.urllib.parse import urlparse
from weaver.config import get_weaver_configuration
from weaver.database import get_db
from weaver.owsexceptions import OWSNoApplicableCode
from weaver.store.base import StoreProcesses
from weaver.utils import get_settings, get_weaver_url
from weaver.visibility import VISIBILITY_PUBLIC
LOGGER = logging.getLogger(__name__)
if TYPE_CHECKING:
from weaver.typedefs import AnySettingsContainer # noqa: F401
from typing import AnyStr, Dict, Union, Optional # noqa: F401
# PyWPS global config
WEAVER_PYWPS_CFG = None # type: Optional[ConfigParser]
def _get_settings_or_wps_config(container, # type: AnySettingsContainer
weaver_setting_name, # type: AnyStr
config_setting_section, # type: AnyStr
config_setting_name, # type: AnyStr
default_not_found, # type: AnyStr
message_not_found, # type: AnyStr
): # type: (...) -> AnyStr
global WEAVER_PYWPS_CFG # pylint: disable=W0603,global-statement
settings = get_settings(container)
found = settings.get(weaver_setting_name)
if not found:
if not WEAVER_PYWPS_CFG:
load_pywps_cfg(container)
found = WEAVER_PYWPS_CFG.get(config_setting_section, config_setting_name)
if not isinstance(found, six.string_types):
LOGGER.warning("%s not set in settings or WPS configuration, using default value.", message_not_found)
found = default_not_found
return found.strip()
def get_wps_path(container):
# type: (AnySettingsContainer) -> AnyStr
"""
Retrieves the WPS path (without hostname).
Searches directly in settings, then `weaver.wps_cfg` file, or finally, uses the default values if not found.
"""
return _get_settings_or_wps_config(container, "weaver.wps_path", "server", "url", "/ows/wps", "WPS path")
def get_wps_url(container):
# type: (AnySettingsContainer) -> AnyStr
"""
Retrieves the full WPS URL (hostname + WPS path).
Searches directly in settings, then `weaver.wps_cfg` file, or finally, uses the default values if not found.
"""
return get_weaver_url(container) + get_wps_path(container)
def get_wps_output_dir(container):
# type: (AnySettingsContainer) -> AnyStr
"""
Retrieves the WPS output directory path where to write XML and result files.
Searches directly in settings, then `weaver.wps_cfg` file, or finally, uses the default values if not found.
"""
tmp_dir = tempfile.gettempdir()
return _get_settings_or_wps_config(container, "weaver.wps_output_dir",
"server", "outputpath", tmp_dir, "WPS output directory")
def get_wps_output_path(container):
# type: (AnySettingsContainer) -> AnyStr
"""
Retrieves the WPS output path (without hostname) for staging XML status, logs and process outputs.
Searches directly in settings, then `weaver.wps_cfg` file, or finally, uses the default values if not found.
"""
return get_settings(container).get("weaver.wps_output_path") or urlparse(get_wps_output_url(container)).path
def get_wps_output_url(container):
# type: (AnySettingsContainer) -> AnyStr
"""
Retrieves the WPS output URL that maps to WPS output directory path.
Searches directly in settings, then `weaver.wps_cfg` file, or finally, uses the default values if not found.
"""
wps_output_default = get_weaver_url(container) + "/wpsoutputs"
return _get_settings_or_wps_config(
container, "weaver.wps_output_url", "server", "outputurl", wps_output_default, "WPS output url")
def load_pywps_cfg(container, config=None):
# type: (AnySettingsContainer, Optional[Union[AnyStr, Dict[AnyStr, AnyStr]]]) -> ConfigParser
"""Loads and updates the PyWPS configuration using Weaver settings."""
global WEAVER_PYWPS_CFG # pylint: disable=W0603,global-statement
settings = get_settings(container)
if WEAVER_PYWPS_CFG is None:
# initial setup of PyWPS config
pywps_config.load_configuration([]) # load defaults
WEAVER_PYWPS_CFG = pywps_config.CONFIG # update reference
# must be set to INFO to disable sqlalchemy trace.
# see : https://github.com/geopython/pywps/blob/master/pywps/dblog.py#L169
if logging.getLevelName(WEAVER_PYWPS_CFG.get("logging", "level")) <= logging.DEBUG:
WEAVER_PYWPS_CFG.set("logging", "level", "INFO")
# update metadata
for setting_name, setting_value in settings.items():
if setting_name.startswith("weaver.wps_metadata"):
WEAVER_PYWPS_CFG.set("metadata:main", setting_name.replace("weaver.wps_metadata", ""), setting_value)
# add weaver configuration keyword if not already provided
wps_keywords = WEAVER_PYWPS_CFG.get("metadata:main", "identification_keywords")
weaver_mode = get_weaver_configuration(settings)
if weaver_mode not in wps_keywords:
wps_keywords += ("," if wps_keywords else "") + weaver_mode
WEAVER_PYWPS_CFG.set("metadata:main", "identification_keywords", wps_keywords)
# add additional config passed as dictionary of {'section.key': 'value'}
if isinstance(config, dict):
for key, value in config.items():
section, key = key.split(".")
WEAVER_PYWPS_CFG.set(section, key, value)
# cleanup alternative dict "PYWPS_CFG" which is not expected elsewhere
if isinstance(settings.get("PYWPS_CFG"), dict):
del settings["PYWPS_CFG"]
# find output directory from app config or wps config
if "weaver.wps_output_dir" not in settings:
output_dir = pywps_config.get_config_value("server", "outputpath")
settings["weaver.wps_output_dir"] = output_dir
# ensure the output dir exists if specified
output_dir = get_wps_output_dir(settings)
if not os.path.isdir(output_dir):
os.makedirs(output_dir)
# find output url from app config (path/url) or wps config (url only)
if "weaver.wps_output_url" not in settings:
output_path = settings.get("weaver.wps_output_path", "")
if isinstance(output_path, six.string_types):
output_url = os.path.join(get_weaver_url(settings), output_path.strip("/"))
else:
output_url = pywps_config.get_config_value("server", "outputurl")
settings["weaver.wps_output_url"] = output_url
# enforce back resolved values onto PyWPS config
WEAVER_PYWPS_CFG.set("server", "setworkdir", "true")
WEAVER_PYWPS_CFG.set("server", "sethomedir", "true")
WEAVER_PYWPS_CFG.set("server", "outputpath", settings["weaver.wps_output_dir"])
WEAVER_PYWPS_CFG.set("server", "outputurl", settings["weaver.wps_output_url"])
return WEAVER_PYWPS_CFG
# @app.task(bind=True)
@wsgiapp2
def pywps_view(environ, start_response):
"""
* TODO: add xml response renderer
"""
LOGGER.debug("pywps env: %s", environ.keys())
try:
# get config file
settings = get_settings(app)
pywps_cfg = environ.get("PYWPS_CFG") or settings.get("PYWPS_CFG") or os.getenv("PYWPS_CFG")
if not isinstance(pywps_cfg, ConfigParser):
load_pywps_cfg(app, config=pywps_cfg)
# call pywps application with processes filtered according to the adapter"s definition
process_store = get_db(app).get_store(StoreProcesses)
processes_wps = [process.wps() for process in
process_store.list_processes(visibility=VISIBILITY_PUBLIC, request=get_current_request())]
service = Service(processes_wps)
except Exception as ex:
LOGGER.exception("Error occurred during PyWPS Service and/or Processes setup.")
raise OWSNoApplicableCode("Failed setup of PyWPS Service and/or Processes. Error [{!r}]".format(ex))
return service(environ, start_response)
def includeme(config):
settings = get_settings(config)
if asbool(settings.get("weaver.wps", True)):
LOGGER.debug("Weaver WPS enabled.")
config.include("weaver.config")
wps_path = get_wps_path(settings)
config.add_route("wps", wps_path)
config.add_view(pywps_view, route_name="wps")