pywcmp 0.14.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pywcmp/__init__.py ADDED
@@ -0,0 +1,47 @@
1
+ ###############################################################################
2
+ #
3
+ # Authors: Tom Kralidis <tomkralidis@gmail.com>
4
+ # Ján Osuský <jan.osusky@iblsoft.com>
5
+ #
6
+ # Copyright (c) 2026 Tom Kralidis
7
+ # Copyright (c) 2022 Government of Canada
8
+ # Copyright (c) 2020 IBL Software Engineering spol. s r. o.
9
+ #
10
+ # Licensed to the Apache Software Foundation (ASF) under one
11
+ # or more contributor license agreements. See the NOTICE file
12
+ # distributed with this work for additional information
13
+ # regarding copyright ownership. The ASF licenses this file
14
+ # to you under the Apache License, Version 2.0 (the
15
+ # "License"); you may not use this file except in compliance
16
+ # with the License. You may obtain a copy of the License at
17
+ #
18
+ # http://www.apache.org/licenses/LICENSE-2.0
19
+ #
20
+ # Unless required by applicable law or agreed to in writing,
21
+ # software distributed under the License is distributed on an
22
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23
+ # KIND, either express or implied. See the License for the
24
+ # specific language governing permissions and limitations
25
+ # under the License.
26
+ #
27
+ ###############################################################################
28
+
29
+ import click
30
+
31
+ from pywcmp.ets import ets
32
+ from pywcmp.bundle import bundle
33
+ from pywcmp.kpi import kpi
34
+ from pywcmp.util import get_package_version
35
+
36
+ __version__ = get_package_version()
37
+
38
+
39
+ @click.group()
40
+ @click.version_option(version=__version__)
41
+ def cli():
42
+ pass
43
+
44
+
45
+ cli.add_command(ets)
46
+ cli.add_command(bundle)
47
+ cli.add_command(kpi)
pywcmp/bundle.py ADDED
@@ -0,0 +1,130 @@
1
+ ###############################################################################
2
+ #
3
+ # Authors: Tom Kralidis <tomkralidis@gmail.com>
4
+ #
5
+ # Copyright (c) 2025 Tom Kralidis
6
+ #
7
+ # Licensed to the Apache Software Foundation (ASF) under one
8
+ # or more contributor license agreements. See the NOTICE file
9
+ # distributed with this work for additional information
10
+ # regarding copyright ownership. The ASF licenses this file
11
+ # to you under the Apache License, Version 2.0 (the
12
+ # "License"); you may not use this file except in compliance
13
+ # with the License. You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # Unless required by applicable law or agreed to in writing,
18
+ # software distributed under the License is distributed on an
19
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ # KIND, either express or implied. See the License for the
21
+ # specific language governing permissions and limitations
22
+ # under the License.
23
+ #
24
+ ###############################################################################
25
+
26
+ import io
27
+ import logging
28
+ import os
29
+ from pathlib import Path
30
+ import shutil
31
+ import tempfile
32
+ import zipfile
33
+
34
+ import click
35
+
36
+ from pywcmp.util import (get_cli_common_options, get_userdir, urlopen_,
37
+ setup_logger)
38
+
39
+ LOGGER = logging.getLogger(__name__)
40
+
41
+ USERDIR = get_userdir()
42
+
43
+ TEMPDIR = tempfile.TemporaryDirectory()
44
+ TEMPDIR2 = Path(tempfile.TemporaryDirectory().name)
45
+
46
+ WCMP2_FILES_TEMP = TEMPDIR2 / 'wcmp-2'
47
+ WIS2_TOPIC_HIERARCHY_DIR_TEMP = TEMPDIR2 / 'wis2-topic-hierarchy'
48
+
49
+ WCMP2_FILES = get_userdir() / 'wcmp-2'
50
+ WIS2_TOPIC_HIERARCHY_DIR = get_userdir() / 'wis2-topic-hierarchy'
51
+
52
+
53
+ @click.group()
54
+ def bundle():
55
+ """Configuration bundle management"""
56
+ pass
57
+
58
+
59
+ @click.command()
60
+ @get_cli_common_options
61
+ @click.pass_context
62
+ def sync(ctx, logfile, verbosity):
63
+ """Sync configuration bundle"""
64
+
65
+ setup_logger(verbosity, logfile)
66
+ LOGGER.debug('Caching schemas, codelists and topic hierarchy')
67
+
68
+ LOGGER.debug('Caching WCMP2 artifacts')
69
+ LOGGER.debug(f'Downloading WCMP2 schema to {WCMP2_FILES_TEMP}')
70
+ WCMP2_FILES_TEMP.mkdir(parents=True, exist_ok=True)
71
+ WCMP2_SCHEMA = 'https://raw.githubusercontent.com/wmo-im/wcmp2/main/schemas/wcmp2-bundled.json' # noqa
72
+
73
+ json_schema = WCMP2_FILES_TEMP / 'wcmp2-bundled.json'
74
+ with json_schema.open('wb') as fh:
75
+ fh.write(urlopen_(f'{WCMP2_SCHEMA}').read())
76
+
77
+ WCMP2_CODELISTS = WCMP2_FILES_TEMP / 'codelists'
78
+ LOGGER.debug(f'Downloading WCMP2 codelists to {WCMP2_CODELISTS}')
79
+ WCMP2_CODELISTS.mkdir(parents=True, exist_ok=True)
80
+ CODELISTS_URL = 'https://github.com/wmo-im/wcmp2-codelists/archive/refs/heads/main.zip' # noqa
81
+ FH = io.BytesIO(urlopen_(CODELISTS_URL).read())
82
+ with zipfile.ZipFile(FH) as z:
83
+ LOGGER.debug(f'Processing zipfile "{z.filename}"')
84
+ for name in z.namelist():
85
+ LOGGER.debug(f'Processing entry "{name}"')
86
+ if '.csv' in name:
87
+ filename = os.path.basename(name)
88
+
89
+ if not filename:
90
+ continue
91
+
92
+ dest_file = WCMP2_CODELISTS / filename
93
+ LOGGER.debug(f'Creating "{dest_file}"')
94
+ with z.open(name) as src, dest_file.open('wb') as dest:
95
+ shutil.copyfileobj(src, dest)
96
+
97
+ LOGGER.debug('Downloading WIS2 topic hierarchy')
98
+ WIS2_TOPIC_HIERARCHY_DIR_TEMP.mkdir(parents=True, exist_ok=True)
99
+
100
+ ZIPFILE_URL = 'https://wmo-im.github.io/wis2-topic-hierarchy/wth-bundle.zip' # noqa
101
+ FH = io.BytesIO(urlopen_(ZIPFILE_URL).read())
102
+ with zipfile.ZipFile(FH) as z:
103
+ LOGGER.debug(f'Processing zipfile "{z.filename}"')
104
+ for name in z.namelist():
105
+ LOGGER.debug(f'Processing entry "{name}"')
106
+ filename = os.path.basename(name)
107
+
108
+ dest_file = WIS2_TOPIC_HIERARCHY_DIR_TEMP / filename
109
+ LOGGER.debug(f'Creating "{dest_file}"')
110
+ with z.open(name) as src, dest_file.open('wb') as dest:
111
+ shutil.copyfileobj(src, dest)
112
+
113
+ LOGGER.debug('Downloading IANA link relations')
114
+ IANA_URL = 'https://www.iana.org/assignments/link-relations/link-relations-1.csv' # noqa
115
+ iana_file = WCMP2_FILES_TEMP / 'link-relations-1.csv'
116
+ with iana_file.open('wb') as fh:
117
+ fh.write(urlopen_(f'{IANA_URL}').read())
118
+
119
+ LOGGER.debug(f'Removing {USERDIR}')
120
+ if USERDIR.exists():
121
+ shutil.rmtree(USERDIR)
122
+
123
+ LOGGER.debug(f'Moving files from {TEMPDIR2} to {USERDIR}')
124
+ shutil.move(TEMPDIR2, USERDIR)
125
+
126
+ LOGGER.debug(f'Cleaning up {TEMPDIR}')
127
+ TEMPDIR.cleanup()
128
+
129
+
130
+ bundle.add_command(sync)
pywcmp/errors.py ADDED
@@ -0,0 +1,31 @@
1
+ ###############################################################################
2
+ #
3
+ # Authors: Tom Kralidis <tomkralidis@gmail.com>
4
+ #
5
+ # Copyright (c) 2022 Tom Kralidis
6
+ #
7
+ # Licensed to the Apache Software Foundation (ASF) under one
8
+ # or more contributor license agreements. See the NOTICE file
9
+ # distributed with this work for additional information
10
+ # regarding copyright ownership. The ASF licenses this file
11
+ # to you under the Apache License, Version 2.0 (the
12
+ # "License"); you may not use this file except in compliance
13
+ # with the License. You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # Unless required by applicable law or agreed to in writing,
18
+ # software distributed under the License is distributed on an
19
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ # KIND, either express or implied. See the License for the
21
+ # specific language governing permissions and limitations
22
+ # under the License.
23
+ #
24
+ ###############################################################################
25
+
26
+ class TestSuiteError(Exception):
27
+ """custom exception handler"""
28
+ def __init__(self, message, errors):
29
+ """set error list/stack"""
30
+ super(TestSuiteError, self).__init__(message)
31
+ self.errors = errors
pywcmp/ets.py ADDED
@@ -0,0 +1,91 @@
1
+ ###############################################################################
2
+ #
3
+ # Authors: Tom Kralidis <tomkralidis@gmail.com>
4
+ # Ján Osuský <jan.osusky@iblsoft.com>
5
+ #
6
+ # Copyright (c) 2025 Tom Kralidis
7
+ # Copyright (c) 2022 Government of Canada
8
+ # Copyright (c) 2020 IBL Software Engineering spol. s r. o.
9
+ #
10
+ # Licensed to the Apache Software Foundation (ASF) under one
11
+ # or more contributor license agreements. See the NOTICE file
12
+ # distributed with this work for additional information
13
+ # regarding copyright ownership. The ASF licenses this file
14
+ # to you under the Apache License, Version 2.0 (the
15
+ # "License"); you may not use this file except in compliance
16
+ # with the License. You may obtain a copy of the License at
17
+ #
18
+ # http://www.apache.org/licenses/LICENSE-2.0
19
+ #
20
+ # Unless required by applicable law or agreed to in writing,
21
+ # software distributed under the License is distributed on an
22
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23
+ # KIND, either express or implied. See the License for the
24
+ # specific language governing permissions and limitations
25
+ # under the License.
26
+ #
27
+ ###############################################################################
28
+
29
+ # executable test for WCMP2
30
+
31
+ import json
32
+
33
+ import click
34
+
35
+ from pywcmp.wcmp2.ets import WMOCoreMetadataProfileTestSuite2
36
+ from pywcmp.util import (get_cli_common_options, parse_wcmp, setup_logger,
37
+ urlopen_)
38
+
39
+
40
+ @click.group()
41
+ def ets():
42
+ """executable test suite"""
43
+ pass
44
+
45
+
46
+ @click.command()
47
+ @click.pass_context
48
+ @get_cli_common_options
49
+ @click.argument('file_or_url')
50
+ @click.option('--fail-on-schema-validation/--no-fail-on-schema-validation',
51
+ '-f', default=True,
52
+ help='Stop the ETS on failing schema validation')
53
+ @click.option('--relax-centre-id-checks', '-r', is_flag=True,
54
+ default=False, help='Relax centre identifier based checks')
55
+ def validate(ctx, file_or_url, logfile, verbosity,
56
+ fail_on_schema_validation=True,
57
+ relax_centre_id_checks=False):
58
+ """validate against the abstract test suite"""
59
+
60
+ setup_logger(verbosity, logfile)
61
+
62
+ click.echo(f'Opening {file_or_url}')
63
+
64
+ if file_or_url.startswith('http'):
65
+ content = urlopen_(file_or_url).read()
66
+ else:
67
+ with open(file_or_url) as fh:
68
+ content = fh.read()
69
+
70
+ click.echo(f'Validating {file_or_url}')
71
+
72
+ try:
73
+ data = parse_wcmp(content)
74
+ except Exception as err:
75
+ raise click.ClickException(err)
76
+ ctx.exit(1)
77
+
78
+ click.echo('Detected WCMP2 discovery metadata')
79
+ ts = WMOCoreMetadataProfileTestSuite2(data)
80
+ try:
81
+ results = ts.run_tests(fail_on_schema_validation,
82
+ relax_centre_id_checks)
83
+ except Exception as err:
84
+ raise click.ClickException(err)
85
+ ctx.exit(1)
86
+
87
+ click.echo(json.dumps(results, indent=4))
88
+ ctx.exit(results['summary']['FAILED'])
89
+
90
+
91
+ ets.add_command(validate)
pywcmp/kpi.py ADDED
@@ -0,0 +1,103 @@
1
+ ###############################################################################
2
+ #
3
+ # Authors: Tom Kralidis <tomkralidis@gmail.com>
4
+ # Ján Osuský <jan.osusky@iblsoft.com>
5
+ #
6
+ # Copyright (c) 2023 Tom Kralidis
7
+ # Copyright (c) 2022 Government of Canada
8
+ # Copyright (c) 2020 IBL Software Engineering spol. s r. o.
9
+ #
10
+ # Licensed to the Apache Software Foundation (ASF) under one
11
+ # or more contributor license agreements. See the NOTICE file
12
+ # distributed with this work for additional information
13
+ # regarding copyright ownership. The ASF licenses this file
14
+ # to you under the Apache License, Version 2.0 (the
15
+ # "License"); you may not use this file except in compliance
16
+ # with the License. You may obtain a copy of the License at
17
+ #
18
+ # http://www.apache.org/licenses/LICENSE-2.0
19
+ #
20
+ # Unless required by applicable law or agreed to in writing,
21
+ # software distributed under the License is distributed on an
22
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23
+ # KIND, either express or implied. See the License for the
24
+ # specific language governing permissions and limitations
25
+ # under the License.
26
+ #
27
+ ###############################################################################
28
+
29
+ # WMO Core Metadata Profile Key Performance Indicators (KPIs)
30
+
31
+ import json
32
+ import logging
33
+
34
+ import click
35
+
36
+ from pywcmp.ets import WMOCoreMetadataProfileTestSuite2
37
+ from pywcmp.wcmp2.kpi import (
38
+ WMOCoreMetadataProfileKeyPerformanceIndicators as wcmp_kpis2
39
+ )
40
+ from pywcmp.util import (get_cli_common_options, parse_wcmp, setup_logger,
41
+ urlopen_)
42
+
43
+ LOGGER = logging.getLogger(__name__)
44
+
45
+
46
+ @click.group()
47
+ def kpi():
48
+ """key performance indicators"""
49
+ pass
50
+
51
+
52
+ @click.command()
53
+ @click.pass_context
54
+ @get_cli_common_options
55
+ @click.argument('file_or_url')
56
+ @click.option('--fail-on-ets/--no-fail-on-ets',
57
+ '-f', default=True, help='Stop the KPI on failing ETS')
58
+ @click.option('--summary', '-s', is_flag=True, default=False,
59
+ help='Provide summary of KPI test results')
60
+ @click.option('--kpi', '-k', help='KPI to run, default is all')
61
+ def validate(ctx, file_or_url, summary, kpi, logfile, verbosity,
62
+ fail_on_ets=True):
63
+ """run key performance indicators"""
64
+
65
+ setup_logger(verbosity, logfile)
66
+
67
+ if file_or_url.startswith('http'):
68
+ content = urlopen_(file_or_url).read()
69
+ else:
70
+ with open(file_or_url) as fh:
71
+ content = fh.read()
72
+
73
+ click.echo(f'Validating {file_or_url}')
74
+
75
+ try:
76
+ data = parse_wcmp(content)
77
+ except Exception as err:
78
+ raise click.ClickException(err)
79
+ ctx.exit(1)
80
+
81
+ if fail_on_ets:
82
+ ts = WMOCoreMetadataProfileTestSuite2(data)
83
+ try:
84
+ _ = ts.run_tests(fail_on_schema_validation=True)
85
+ except Exception as err:
86
+ raise click.ClickException(err)
87
+ ctx.exit(1)
88
+
89
+ kpis = wcmp_kpis2(data)
90
+
91
+ try:
92
+ kpis_results = kpis.evaluate(kpi)
93
+ except ValueError as err:
94
+ raise click.UsageError(f'Invalid KPI {kpi}: {err}')
95
+ ctx.exit(1)
96
+
97
+ if not summary or kpi is not None:
98
+ click.echo(json.dumps(kpis_results, indent=4))
99
+ else:
100
+ click.echo(json.dumps(kpis_results['summary'], indent=4))
101
+
102
+
103
+ kpi.add_command(validate)
@@ -0,0 +1,290 @@
1
+ ###############################################################################
2
+ #
3
+ # Authors: Tom Kralidis <tomkralidis@gmail.com>
4
+ #
5
+ # Copyright (c) 2026 Tom Kralidis
6
+ #
7
+ # Licensed to the Apache Software Foundation (ASF) under one
8
+ # or more contributor license agreements. See the NOTICE file
9
+ # distributed with this work for additional information
10
+ # regarding copyright ownership. The ASF licenses this file
11
+ # to you under the Apache License, Version 2.0 (the
12
+ # "License"); you may not use this file except in compliance
13
+ # with the License. You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # Unless required by applicable law or agreed to in writing,
18
+ # software distributed under the License is distributed on an
19
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ # KIND, either express or implied. See the License for the
21
+ # specific language governing permissions and limitations
22
+ # under the License.
23
+ #
24
+ ###############################################################################
25
+
26
+ #
27
+ # pywcmp as a service
28
+ # -------------------
29
+ #
30
+ # This file is intended to be used as a pygeoapi process plugin which will
31
+ # provide pywcmp functionality via OGC API - Processes.
32
+ #
33
+ # To integrate this plugin in pygeoapi:
34
+ #
35
+ # 1. ensure pywcmp is installed into the pygeoapi deployment environment
36
+ #
37
+ # 2. add the processes to the pygeoapi configuration as follows:
38
+ #
39
+ # pywcmp-wis2-wcmp2-ets:
40
+ # type: process
41
+ # processor:
42
+ # name: pywcmp.pygeoapi_plugin.WCMP2ETSProcessor
43
+ #
44
+ # pywcmp-wis2-wcmp2-kpi:
45
+ # type: process
46
+ # processor:
47
+ # name: pywcmp.pygeoapi_plugin.WCMP2KPIProcessor
48
+ #
49
+ # 3. (re)start pygeoapi
50
+ #
51
+ # The resulting processes will be available at the following endpoints:
52
+ #
53
+ # /processes/pywcmp-wis2-wcmp2-ets
54
+ #
55
+ # /processes/pywcmp-wis2-wcmp2-kpi
56
+ #
57
+ # Note that pygeoapi's OpenAPI/Swagger interface (at /openapi) will also
58
+ # provide a developer-friendly interface to test and run requests
59
+ #
60
+
61
+
62
+ import json
63
+ import logging
64
+
65
+ from pygeoapi.process.base import BaseProcessor, ProcessorExecuteError
66
+
67
+ from pywcmp.wcmp2.ets import WMOCoreMetadataProfileTestSuite2
68
+ from pywcmp.wcmp2.kpi import WMOCoreMetadataProfileKeyPerformanceIndicators
69
+ from pywcmp.util import get_package_version, THISDIR, urlopen_
70
+
71
+ LOGGER = logging.getLogger(__name__)
72
+
73
+ with (THISDIR / 'resources' / 'ets-report.json').open() as fh:
74
+ ETS_REPORT_SCHEMA = json.load(fh)
75
+
76
+ with (THISDIR / 'resources' / 'kpi-report.json').open() as fh:
77
+ KPI_REPORT_SCHEMA = json.load(fh)
78
+
79
+ with (THISDIR / 'resources' / 'example-ca-eccc-msc.nwp-gdps.json').open() as fh: # noqa
80
+ EXAMPLE_WCMP2 = json.load(fh)
81
+
82
+
83
+ PROCESS_WCMP2_ETS = {
84
+ 'version': get_package_version(),
85
+ 'id': 'pywcmp-wis2-wcmp2-ets',
86
+ 'title': {
87
+ 'en': 'WCMP2 ETS validator'
88
+ },
89
+ 'description': {
90
+ 'en': 'Validate a WCMP2 document against the ETS'
91
+ },
92
+ 'keywords': ['wis2', 'wcmp2', 'ets', 'test suite', 'metadata'],
93
+ 'links': [{
94
+ 'type': 'text/html',
95
+ 'rel': 'about',
96
+ 'title': 'information',
97
+ 'href': 'https://wmo-im.github.io/wcmp2',
98
+ 'hreflang': 'en-US'
99
+ }],
100
+ 'jobControlOptions': ['sync-execute', 'async-execute'],
101
+ 'inputs': {
102
+ 'record': {
103
+ 'title': 'WCMP2 record',
104
+ 'description': 'WCMP2 record (can be inline or remote link)',
105
+ 'schema': {
106
+ 'type': ['object', 'string']
107
+ },
108
+ 'minOccurs': 1,
109
+ 'maxOccurs': 1,
110
+ 'metadata': None,
111
+ 'keywords': ['wcmp2']
112
+ },
113
+ 'fail_on_schema_validation': {
114
+ 'title': 'Fail on schema validation',
115
+ 'description': 'Stop the ETS on failing schema validation',
116
+ 'schema': {
117
+ 'type': 'boolean',
118
+ 'default': True
119
+ },
120
+ 'minOccurs': 0,
121
+ 'maxOccurs': 1,
122
+ 'metadata': None,
123
+ 'keywords': ['schema', 'validation']
124
+ },
125
+ 'relax_centre_id_checks': {
126
+ 'title': 'Skip centre identifier checks',
127
+ 'description': 'Skip centre identifier checks from failing',
128
+ 'schema': {
129
+ 'type': 'boolean',
130
+ 'default': False
131
+ },
132
+ 'minOccurs': 0,
133
+ 'maxOccurs': 1,
134
+ 'metadata': None,
135
+ 'keywords': ['centre identifier']
136
+ }
137
+ },
138
+ 'outputs': {
139
+ 'result': {
140
+ 'title': 'Report of ETS results',
141
+ 'description': 'Report of ETS results',
142
+ 'schema': {
143
+ 'contentMediaType': 'application/json',
144
+ **ETS_REPORT_SCHEMA
145
+ }
146
+ }
147
+ },
148
+ 'example': {
149
+ 'inputs': {
150
+ 'record': EXAMPLE_WCMP2,
151
+ 'fail_on_schema_validation': True,
152
+ 'relax_centre_id_checks': False
153
+ }
154
+ }
155
+ }
156
+
157
+
158
+ PROCESS_WCMP2_KPI = {
159
+ 'version': get_package_version(),
160
+ 'id': 'pywcmp-wis2-wcmp2-kpi',
161
+ 'title': {
162
+ 'en': 'WCMP2 KPI evaluator'
163
+ },
164
+ 'description': {
165
+ 'en': 'Validate a WCMP2 document against the KPI suite'
166
+ },
167
+ 'keywords': ['wis2', 'wcmp2', 'kpi', 'test suite', 'metadata'],
168
+ 'links': [{
169
+ 'type': 'text/html',
170
+ 'rel': 'about',
171
+ 'title': 'information',
172
+ 'href': 'https://wmo-im.github.io/wcmp2',
173
+ 'hreflang': 'en-US'
174
+ }],
175
+ 'jobControlOptions': ['sync-execute', 'async-execute'],
176
+ 'inputs': {
177
+ 'record': {
178
+ 'title': 'WCMP2 record',
179
+ 'description': 'WCMP2 record (can be inline or remote link)',
180
+ 'schema': {
181
+ 'type': ['object', 'string']
182
+ },
183
+ 'minOccurs': 1,
184
+ 'maxOccurs': 1,
185
+ 'metadata': None,
186
+ 'keywords': ['wcmp2']
187
+ }
188
+ },
189
+ 'outputs': {
190
+ 'result': {
191
+ 'title': 'Report of KPI results',
192
+ 'description': 'Report of KPI results',
193
+ 'schema': {
194
+ 'contentMediaType': 'application/json',
195
+ **KPI_REPORT_SCHEMA
196
+ }
197
+ }
198
+ },
199
+ 'example': {
200
+ 'inputs': {
201
+ 'record': EXAMPLE_WCMP2
202
+ }
203
+ }
204
+ }
205
+
206
+
207
+ class WCMP2ETSProcessor(BaseProcessor):
208
+ """WCMP2 ETS"""
209
+
210
+ def __init__(self, processor_def):
211
+ """
212
+ Initialize object
213
+
214
+ :param processor_def: provider definition
215
+
216
+ :returns: pywcmp.pygeoapi_plugin.WCMP2ETSProcessor
217
+ """
218
+
219
+ super().__init__(processor_def, PROCESS_WCMP2_ETS)
220
+
221
+ def execute(self, data, outputs=None):
222
+
223
+ response = None
224
+ mimetype = 'application/json'
225
+ record = data.get('record')
226
+ fail_on_schema_validation = data.get('fail_on_schema_validation', True)
227
+ relax_centre_id_checks = data.get('relax_centre_id_checks', False)
228
+
229
+ if record is None:
230
+ msg = 'Missing record'
231
+ LOGGER.error(msg)
232
+ raise ProcessorExecuteError(msg)
233
+
234
+ if isinstance(record, str) and record.startswith('http'):
235
+ LOGGER.debug('Record is a link')
236
+ record = json.loads(urlopen_(record).read())
237
+ else:
238
+ LOGGER.debug('Record is inline')
239
+
240
+ LOGGER.debug('Running ETS against record')
241
+ response = WMOCoreMetadataProfileTestSuite2(record).run_tests(
242
+ fail_on_schema_validation=fail_on_schema_validation,
243
+ relax_centre_id_checks=relax_centre_id_checks)
244
+
245
+ return mimetype, response
246
+
247
+ def __repr__(self):
248
+ return '<WCMP2ETSProcessor>'
249
+
250
+
251
+ class WCMP2KPIProcessor(BaseProcessor):
252
+ """WCMP2 KPI"""
253
+
254
+ def __init__(self, processor_def):
255
+ """
256
+ Initialize object
257
+
258
+ :param processor_def: provider definition
259
+
260
+ :returns: pywcmp.pygeoapi_plugin.WCMP2KPIProcessor
261
+ """
262
+
263
+ super().__init__(processor_def, PROCESS_WCMP2_KPI)
264
+
265
+ def execute(self, data, outputs=None):
266
+
267
+ response = None
268
+ mimetype = 'application/json'
269
+
270
+ record = data.get('record')
271
+
272
+ if record is None:
273
+ msg = 'Missing record'
274
+ LOGGER.error(msg)
275
+ raise ProcessorExecuteError(msg)
276
+
277
+ if isinstance(record, str) and record.startswith('http'):
278
+ LOGGER.debug('Record is a link')
279
+ record = json.loads(urlopen_(record).read())
280
+ else:
281
+ LOGGER.debug('Record is inline')
282
+
283
+ LOGGER.debug('Running KPIs against record')
284
+ kpis = WMOCoreMetadataProfileKeyPerformanceIndicators(record)
285
+ response = kpis.evaluate()
286
+
287
+ return mimetype, response
288
+
289
+ def __repr__(self):
290
+ return '<WCMP2KPIProcessor>'
@@ -0,0 +1,2 @@
1
+ # add custom dictionary words below (one per line)
2
+ # as part of spellchecker functionality