pywmdr 0.2.dev0__tar.gz

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.
@@ -0,0 +1,24 @@
1
+ Authors:
2
+
3
+ Tom Kralidis <tomkralidis@gmail.com>
4
+
5
+ Copyright (c) 2025 Tom Kralidis
6
+
7
+ ***
8
+
9
+ Licensed to the Apache Software Foundation (ASF) under one
10
+ or more contributor license agreements. See the NOTICE file
11
+ distributed with this work for additional information
12
+ regarding copyright ownership. The ASF licenses this file
13
+ to you under the Apache License, Version 2.0 (the
14
+ "License"); you may not use this file except in compliance
15
+ with the License. You may obtain a copy of the License at
16
+
17
+ http://www.apache.org/licenses/LICENSE-2.0
18
+
19
+ Unless required by applicable law or agreed to in writing,
20
+ software distributed under the License is distributed on an
21
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22
+ KIND, either express or implied. See the License for the
23
+ specific language governing permissions and limitations
24
+ under the License.
@@ -0,0 +1,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: pywmdr
3
+ Version: 0.2.dev0
4
+ Summary: A Python implementation of the test suite for WIGOS Metadata Record
5
+ Author-email: Tom Kralidis <tomkralidis@gmail.com>
6
+ Maintainer-email: Tom Kralidis <tomkralidis@gmail.com>
7
+ License-Expression: Apache-2.0
8
+ Project-URL: homepage, https://github.com/wmo-im/pywmdr
9
+ Project-URL: source, https://github.com/wmo-im/pywmdr
10
+ Project-URL: documentation, https://github.com/wmo-im/pywmdr
11
+ Project-URL: issues, https://github.com/wmo-im/pywmdr/issues
12
+ Keywords: wmo,wigos,station metadata,test suite
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
20
+ Classifier: Topic :: Scientific/Engineering :: GIS
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE.md
24
+ Requires-Dist: click
25
+ Requires-Dist: jsonschema
26
+ Requires-Dist: rfc3339-validator
27
+ Requires-Dist: rfc3987
28
+ Requires-Dist: shapely
29
+ Provides-Extra: dev
30
+ Requires-Dist: flake8; extra == "dev"
31
+ Provides-Extra: release
32
+ Requires-Dist: build; extra == "release"
33
+ Requires-Dist: twine; extra == "release"
34
+ Requires-Dist: wheel; extra == "release"
35
+ Provides-Extra: test
36
+ Requires-Dist: pytest; extra == "test"
37
+ Dynamic: license-file
38
+
39
+ # pywmdr
40
+
41
+ [![Build Status](https://github.com/wmo-im/pywmdr/workflows/build%20%E2%9A%99%EF%B8%8F/badge.svg)](https://github.com/wmo-im/pywmdr/actions)
42
+
43
+ # WIGOS Metadata Record Test Suite
44
+
45
+ pywmdr provides validation and quality assessment capabilities for the [WIGOS Metadata Record](https://wmo-im.github.io/wmdr2) (WMDR2) standard.
46
+
47
+ - validation against [WMDR2](https://wmo-im.github.io/wmdr2/standard/wmdr2-DRAFT.html), specifically [Annex A: Conformance Class Abstract Test Suite](https://wmo-im.github.io/wmdr2/standard/wmdr2-DRAFT.html#_conformance_class_abstract_test_suite_normative)), implementing an executable test suite against the ATS
48
+
49
+ ## Installation
50
+
51
+ ### pip
52
+
53
+ Install latest stable version from [PyPI](https://pypi.org/project/pywmdr).
54
+
55
+ ```bash
56
+ pip3 install pywmdr
57
+ ```
58
+
59
+ ### From source
60
+
61
+ Install latest development version.
62
+
63
+ ```bash
64
+ python3 -m venv pywmdr
65
+ cd pywmdr
66
+ . bin/activate
67
+ git clone https://github.com/wmo-im/pywmdr.git
68
+ cd pywmdr
69
+ pip3 install .
70
+ ```
71
+
72
+ ## Running
73
+
74
+ From command line:
75
+ ```bash
76
+ # fetch version
77
+ pywmdr --version
78
+
79
+ # sync supporting configuration bundle (schemas, topics, etc.)
80
+ pywmdr bundle sync
81
+
82
+ # abstract test suite
83
+
84
+ # validate WMDR2 metadata against abstract test suite (file on disk)
85
+ pywmdr ets validate /path/to/file.json
86
+
87
+ # validate WMDR2 metadata against abstract test suite (URL)
88
+ pywmdr ets validate https://example.org/path/to/file.json
89
+
90
+ # validate WMDR2 metadata against abstract test suite (URL), but turn JSON Schema validation off
91
+ pywmdr ets validate https://example.org/path/to/file.json --no-fail-on-schema-validation
92
+
93
+ # adjust debugging messages (CRITICAL, ERROR, WARNING, INFO, DEBUG) to stdout
94
+ pywmdr ets validate https://example.org/path/to/file.json --verbosity DEBUG
95
+
96
+ # write results to logfile
97
+ pywmdr ets validate https://example.org/path/to/file.json --verbosity DEBUG --logfile /tmp/foo.txt
98
+ ```
99
+
100
+ ## Using the API
101
+ ```pycon
102
+ >>> # test a file on disk
103
+ >>> import json
104
+ >>> from pywmdr.wmdr2.ets import WIGOSMetadataRepresentationTestSuite2
105
+ >>> from pywmdr.errors import TestSuiteError
106
+ >>> with open('/path/to/file.json') as fh:
107
+ ... data = json.load(fh)
108
+ >>> # test ETS
109
+ >>> ts = WMOCoreMetadataProfileTestSuite2(datal)
110
+ >>> ts.run_tests()
111
+ >>> ts.raise_for_status() # raises pywmdr.errors.TestSuiteError on exception with list of errors captured in .errors property
112
+ >>> # test a URL
113
+ >>> from urllib2 import urlopen
114
+ >>> from StringIO import StringIO
115
+ >>> content = StringIO(urlopen('https://....').read())
116
+ >>> data = json.loads(content)
117
+ >>> ts = WMOCoreMetadataProfileTestSuite2(data)
118
+ >>> ts.run_tests()
119
+ >>> ts.raise_for_status() # raises pywmdr.errors.TestSuiteError on exception with list of errors captured in .errors property
120
+ ```
121
+
122
+ ## Development
123
+
124
+ ```bash
125
+ python3 -m venv pywmdr
126
+ cd pywmdr
127
+ source bin/activate
128
+ git clone https://github.com/World-Meteorological-Organization/pywmdr.git
129
+ pip3 install .
130
+ pip3 install ".[dev]"
131
+ ```
132
+
133
+ ### Running tests
134
+
135
+ ```bash
136
+ pytest tests
137
+ ```
138
+
139
+ ## Releasing
140
+
141
+ ```bash
142
+ # create release (x.y.z is the release version)
143
+ vi pyproject.toml # update [project]/version
144
+ git commit -am 'update release version x.y.z'
145
+ git push origin master
146
+ git tag -a x.y.z -m 'tagging release version x.y.z'
147
+ git push --tags
148
+
149
+ # upload to PyPI
150
+ rm -fr build dist *.egg-info
151
+ python3 -m build
152
+ twine upload dist/*
153
+
154
+ # publish release on GitHub (https://github.com/wmo-im/pywmdr/releases/new)
155
+
156
+ # bump version back to dev
157
+ vi pyproject.toml # update [project]/version
158
+ git commit -am 'back to dev'
159
+ git push origin master
160
+ ```
161
+
162
+ ## Code Conventions
163
+
164
+ [PEP8](https://www.python.org/dev/peps/pep-0008)
165
+
166
+ ## Issues
167
+
168
+ Issues are managed at https://github.com/wmo-im/pywmdr/issues
169
+
170
+ ## Contact
171
+
172
+ * [Tom Kralidis](https://github.com/tomkralidis)
@@ -0,0 +1,134 @@
1
+ # pywmdr
2
+
3
+ [![Build Status](https://github.com/wmo-im/pywmdr/workflows/build%20%E2%9A%99%EF%B8%8F/badge.svg)](https://github.com/wmo-im/pywmdr/actions)
4
+
5
+ # WIGOS Metadata Record Test Suite
6
+
7
+ pywmdr provides validation and quality assessment capabilities for the [WIGOS Metadata Record](https://wmo-im.github.io/wmdr2) (WMDR2) standard.
8
+
9
+ - validation against [WMDR2](https://wmo-im.github.io/wmdr2/standard/wmdr2-DRAFT.html), specifically [Annex A: Conformance Class Abstract Test Suite](https://wmo-im.github.io/wmdr2/standard/wmdr2-DRAFT.html#_conformance_class_abstract_test_suite_normative)), implementing an executable test suite against the ATS
10
+
11
+ ## Installation
12
+
13
+ ### pip
14
+
15
+ Install latest stable version from [PyPI](https://pypi.org/project/pywmdr).
16
+
17
+ ```bash
18
+ pip3 install pywmdr
19
+ ```
20
+
21
+ ### From source
22
+
23
+ Install latest development version.
24
+
25
+ ```bash
26
+ python3 -m venv pywmdr
27
+ cd pywmdr
28
+ . bin/activate
29
+ git clone https://github.com/wmo-im/pywmdr.git
30
+ cd pywmdr
31
+ pip3 install .
32
+ ```
33
+
34
+ ## Running
35
+
36
+ From command line:
37
+ ```bash
38
+ # fetch version
39
+ pywmdr --version
40
+
41
+ # sync supporting configuration bundle (schemas, topics, etc.)
42
+ pywmdr bundle sync
43
+
44
+ # abstract test suite
45
+
46
+ # validate WMDR2 metadata against abstract test suite (file on disk)
47
+ pywmdr ets validate /path/to/file.json
48
+
49
+ # validate WMDR2 metadata against abstract test suite (URL)
50
+ pywmdr ets validate https://example.org/path/to/file.json
51
+
52
+ # validate WMDR2 metadata against abstract test suite (URL), but turn JSON Schema validation off
53
+ pywmdr ets validate https://example.org/path/to/file.json --no-fail-on-schema-validation
54
+
55
+ # adjust debugging messages (CRITICAL, ERROR, WARNING, INFO, DEBUG) to stdout
56
+ pywmdr ets validate https://example.org/path/to/file.json --verbosity DEBUG
57
+
58
+ # write results to logfile
59
+ pywmdr ets validate https://example.org/path/to/file.json --verbosity DEBUG --logfile /tmp/foo.txt
60
+ ```
61
+
62
+ ## Using the API
63
+ ```pycon
64
+ >>> # test a file on disk
65
+ >>> import json
66
+ >>> from pywmdr.wmdr2.ets import WIGOSMetadataRepresentationTestSuite2
67
+ >>> from pywmdr.errors import TestSuiteError
68
+ >>> with open('/path/to/file.json') as fh:
69
+ ... data = json.load(fh)
70
+ >>> # test ETS
71
+ >>> ts = WMOCoreMetadataProfileTestSuite2(datal)
72
+ >>> ts.run_tests()
73
+ >>> ts.raise_for_status() # raises pywmdr.errors.TestSuiteError on exception with list of errors captured in .errors property
74
+ >>> # test a URL
75
+ >>> from urllib2 import urlopen
76
+ >>> from StringIO import StringIO
77
+ >>> content = StringIO(urlopen('https://....').read())
78
+ >>> data = json.loads(content)
79
+ >>> ts = WMOCoreMetadataProfileTestSuite2(data)
80
+ >>> ts.run_tests()
81
+ >>> ts.raise_for_status() # raises pywmdr.errors.TestSuiteError on exception with list of errors captured in .errors property
82
+ ```
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ python3 -m venv pywmdr
88
+ cd pywmdr
89
+ source bin/activate
90
+ git clone https://github.com/World-Meteorological-Organization/pywmdr.git
91
+ pip3 install .
92
+ pip3 install ".[dev]"
93
+ ```
94
+
95
+ ### Running tests
96
+
97
+ ```bash
98
+ pytest tests
99
+ ```
100
+
101
+ ## Releasing
102
+
103
+ ```bash
104
+ # create release (x.y.z is the release version)
105
+ vi pyproject.toml # update [project]/version
106
+ git commit -am 'update release version x.y.z'
107
+ git push origin master
108
+ git tag -a x.y.z -m 'tagging release version x.y.z'
109
+ git push --tags
110
+
111
+ # upload to PyPI
112
+ rm -fr build dist *.egg-info
113
+ python3 -m build
114
+ twine upload dist/*
115
+
116
+ # publish release on GitHub (https://github.com/wmo-im/pywmdr/releases/new)
117
+
118
+ # bump version back to dev
119
+ vi pyproject.toml # update [project]/version
120
+ git commit -am 'back to dev'
121
+ git push origin master
122
+ ```
123
+
124
+ ## Code Conventions
125
+
126
+ [PEP8](https://www.python.org/dev/peps/pep-0008)
127
+
128
+ ## Issues
129
+
130
+ Issues are managed at https://github.com/wmo-im/pywmdr/issues
131
+
132
+ ## Contact
133
+
134
+ * [Tom Kralidis](https://github.com/tomkralidis)
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["setuptools", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pywmdr"
7
+ version = "0.2.dev0"
8
+ description = "A Python implementation of the test suite for WIGOS Metadata Record"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = "Apache-2.0"
12
+ license-files = ["LICENSE.md"]
13
+ keywords = ["wmo", "wigos", "station metadata", "test suite"]
14
+ authors = [
15
+ {name = "Tom Kralidis", email = "tomkralidis@gmail.com"}
16
+ ]
17
+ maintainers = [
18
+ {name = "Tom Kralidis", email = "tomkralidis@gmail.com"}
19
+ ]
20
+ classifiers = [
21
+ "Development Status :: 4 - Beta",
22
+ "Environment :: Console",
23
+ "Intended Audience :: Developers",
24
+ "Intended Audience :: Science/Research",
25
+ "Operating System :: OS Independent",
26
+ "Programming Language :: Python",
27
+ "Topic :: Scientific/Engineering :: Atmospheric Science",
28
+ "Topic :: Scientific/Engineering :: GIS"
29
+ ]
30
+ dependencies = [
31
+ "click",
32
+ "jsonschema",
33
+ "rfc3339-validator",
34
+ "rfc3987",
35
+ "shapely"
36
+ ]
37
+
38
+ [project.optional-dependencies]
39
+ dev = ["flake8"]
40
+ release = ["build", "twine", "wheel"]
41
+ test = ["pytest"]
42
+
43
+ [project.scripts]
44
+ pywmdr = "pywmdr:cli"
45
+
46
+ [project.urls]
47
+ homepage = "https://github.com/wmo-im/pywmdr"
48
+ source = "https://github.com/wmo-im/pywmdr"
49
+ documentation = "https://github.com/wmo-im/pywmdr"
50
+ issues = "https://github.com/wmo-im/pywmdr/issues"
51
+
52
+ [tool.setuptools.packages.find]
53
+ where = ["."]
54
+ exclude = ["tests*"]
55
+
56
+ [tool.setuptools.package-data]
57
+ "pywmdr" = ["*.json", "**/*.json"]
@@ -0,0 +1,42 @@
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
+ import click
27
+
28
+ from pywmdr.record import record
29
+ from pywmdr.bundle import bundle
30
+ from pywmdr.util import get_package_version
31
+
32
+ __version__ = get_package_version()
33
+
34
+
35
+ @click.group()
36
+ @click.version_option(version=__version__)
37
+ def cli():
38
+ pass
39
+
40
+
41
+ cli.add_command(bundle)
42
+ cli.add_command(record)
@@ -0,0 +1,75 @@
1
+ ##############################################################################
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+ ###############################################################################
21
+
22
+ import logging
23
+ from pathlib import Path
24
+ import shutil
25
+ import tempfile
26
+
27
+ import click
28
+
29
+ from pywmdr import cli_options
30
+ from pywmdr.util import get_userdir, urlopen_
31
+
32
+ LOGGER = logging.getLogger(__name__)
33
+
34
+ USERDIR = get_userdir()
35
+
36
+ TEMPDIR = tempfile.TemporaryDirectory()
37
+ TEMPDIR2 = Path(tempfile.TemporaryDirectory().name)
38
+
39
+ WMDR2_FILES = get_userdir() / 'wmdr2'
40
+ WMDR2_FILES_TEMP = TEMPDIR2 / 'wmdr2'
41
+
42
+
43
+ @click.group()
44
+ def bundle():
45
+ """Configuration bundle management"""
46
+ pass
47
+
48
+
49
+ @click.command()
50
+ @click.pass_context
51
+ @cli_options.OPTION_VERBOSITY
52
+ def sync(ctx, verbosity):
53
+ """Sync configuration bundle"""
54
+
55
+ LOGGER.debug('Caching schema')
56
+ LOGGER.debug(f'Downloading WMDR2 schema to {WMDR2_FILES_TEMP}')
57
+ WMDR2_FILES_TEMP.mkdir(parents=True, exist_ok=True)
58
+ WMDR2_SCHEMA = 'https://raw.githubusercontent.com/wmo-im/wmdr2/refs/heads/main/schemas/wmdr2-bundled.json' # noqa
59
+
60
+ json_schema = WMDR2_FILES_TEMP / 'wmdr2-bundled.json'
61
+ with json_schema.open('wb') as fh:
62
+ fh.write(urlopen_(f'{WMDR2_SCHEMA}').read())
63
+
64
+ LOGGER.debug(f'Removing {USERDIR}')
65
+ if USERDIR.exists():
66
+ shutil.rmtree(USERDIR)
67
+
68
+ LOGGER.debug(f'Moving files from {TEMPDIR2} to {USERDIR}')
69
+ shutil.move(TEMPDIR2, USERDIR)
70
+
71
+ LOGGER.debug(f'Cleaning up {TEMPDIR}')
72
+ TEMPDIR.cleanup()
73
+
74
+
75
+ bundle.add_command(sync)
@@ -0,0 +1,45 @@
1
+ ##############################################################################
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+ ###############################################################################
21
+
22
+ import logging
23
+ import sys
24
+
25
+ import click
26
+
27
+
28
+ def OPTION_VERBOSITY(f):
29
+ logging_options = ['ERROR', 'WARNING', 'INFO', 'DEBUG']
30
+
31
+ def callback(ctx, param, value):
32
+ value2 = value or 'INFO'
33
+ logging.basicConfig(stream=sys.stdout,
34
+ level=getattr(logging, value2))
35
+ return True
36
+
37
+ return click.option('--verbosity', '-v',
38
+ type=click.Choice(logging_options),
39
+ help='Verbosity',
40
+ callback=callback)(f)
41
+
42
+
43
+ def cli_callbacks(f):
44
+ f = OPTION_VERBOSITY(f)
45
+ return f
@@ -0,0 +1,27 @@
1
+ ##############################################################################
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+ ###############################################################################
21
+
22
+ class TestSuiteError(Exception):
23
+ """custom exception handler"""
24
+ def __init__(self, message, errors):
25
+ """set error list/stack"""
26
+ super(TestSuiteError, self).__init__(message)
27
+ self.errors = errors