Skip to content

Commit 7ee5066

Browse files
authored
Merge pull request #302 from mpsonntag/convScript
Add format conversion console script LGTM
2 parents b3188df + 2ecfaf2 commit 7ee5066

6 files changed

Lines changed: 172 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@ until the next release.
55

66
# Latest changes in master
77

8+
## Uncertainty changes
9+
10+
Uncertainty is now limited to float only. See #294.
11+
12+
## Version converter changes
13+
14+
The VersionConverter dealt with an edge case of XML test files with opening <B0> tags
15+
that were missing their closing tag rendering them broken. Catching this one edge case
16+
circumvented opening XML files via lxml, leaving the resulting document open to various
17+
encoding problems.
18+
19+
Support to resolve the specific tag edge cases is dropped in favour of properly opening
20+
XML files via lxml. See #301.
21+
22+
## Additional console script
23+
24+
The `odmlconversion` convenience console script has been added to convert multiple
25+
previous odML version files to the latest odML version.
26+
827

928
# Version 1.4.1
1029

doc/conf.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,22 @@
1111
# All configuration values have a default; values that are commented out
1212
# serve to show the default.
1313

14+
import json
1415
import os
16+
import pathlib
1517
import sys
1618

19+
from distutils.version import LooseVersion as CheckVer
20+
21+
currdir = os.path.dirname(os.path.abspath(__file__))
22+
parent = pathlib.Path(currdir).parent
23+
path = os.path.join(parent, "odml", "info.json")
24+
25+
with open(path) as infofile:
26+
infodict = json.load(infofile)
27+
28+
version_str = infodict["VERSION"]
29+
1730
# If extensions (or modules to document with autodoc) are in another directory,
1831
# add these directories to sys.path here. If the directory is relative to the
1932
# documentation root, use os.path.abspath to make it absolute, like shown here.
@@ -69,9 +82,9 @@ def __new__(meta, name, bases, clsdict):
6982
# built documents.
7083
#
7184
# The short X.Y version.
72-
version = '1.4'
85+
version = "%s.%s" % (CheckVer(version_str).version[0], CheckVer(version_str).version[1])
7386
# The full version, including alpha/beta/rc tags.
74-
release = '1.4.1'
87+
release = version_str
7588

7689
# The language for content autogenerated by Sphinx. Refer to documentation
7790
# for a list of supported languages.

odml/info.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"VERSION": "1.4.1",
2+
"VERSION": "1.4.2",
33
"FORMAT_VERSION": "1.1",
44
"AUTHOR": "Hagen Fritsch, Jan Grewe, Christian Kellner, Achilleas Koutsou, Michael Sonntag, Lyuba Zehl",
55
"COPYRIGHT": "(c) 2011-2018, German Neuroinformatics Node",

odml/scripts/odml_conversion.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
"""odmlConversion
2+
3+
odmlConversion searches for odML files within a provided SEARCHDIR
4+
and converts them to the newest odML format version.
5+
Original files will never be overwritten. New files will be
6+
written either to a new directory at the current or a specified
7+
location.
8+
9+
Usage: odmlconversion [-r] [-o OUT] SEARCHDIR
10+
11+
Arguments:
12+
SEARCHDIR Directory to search for odML files.
13+
14+
Options:
15+
-o OUT Output directory. Must exist if specified.
16+
If not specified, output files will be
17+
written to the current directory.
18+
-r Search recursively. Directory structures
19+
will not be retained.
20+
-h --help Show this screen.
21+
--version Show version.
22+
"""
23+
24+
import os
25+
import pathlib
26+
import sys
27+
import tempfile
28+
29+
from docopt import docopt
30+
31+
try:
32+
from StringIO import StringIO
33+
except ImportError:
34+
from io import StringIO
35+
36+
import odml
37+
38+
from odml.tools.version_converter import VersionConverter as VerConf
39+
40+
try:
41+
unicode = unicode
42+
except NameError:
43+
unicode = str
44+
45+
46+
def run_conversion(file_list, output_dir, report, source_format="XML"):
47+
"""
48+
Convert a list of odML files to the latest odML version.
49+
:param file_list: list of files to be converted.
50+
:param output_dir: Directory where odML files converted to
51+
the latest odML version will be saved.
52+
:param report: Reporting StringIO.
53+
:param source_format: Original file format of the odML source files.
54+
XML, JSON and YAML are supported, default is XML.
55+
"""
56+
# Exceptions are kept as broad as possible to ignore any non-odML or
57+
# invalid odML files and ensuring everything that can be will be converted.
58+
for curr_file in file_list:
59+
file_path = unicode(curr_file.absolute())
60+
report.write("[Info] Handling file '%s'\n" % file_path)
61+
# When loading the current file succeeds, it is
62+
# a recent odML format file and can be ignored.
63+
try:
64+
odml.load(file_path, source_format)
65+
report.write("[Info] Skip recent version file '%s'" % file_path)
66+
except Exception as exc:
67+
out_name = os.path.splitext(os.path.basename(file_path))[0]
68+
outfile = os.path.join(output_dir, "%s_conv.xml" % out_name)
69+
try:
70+
VerConf(file_path).write_to_file(outfile, source_format)
71+
except Exception as exc:
72+
# Ignore files we cannot parse or convert
73+
report.write("[Error] version converting file '%s': '%s'\n" %
74+
(file_path, exc))
75+
76+
77+
def main(args=None):
78+
"""
79+
Convenience script to automatically convert odML files
80+
within a directory (tree) to the newest file version.
81+
Check the cli help for details.
82+
:param args: Command line arguments
83+
"""
84+
parser = docopt(__doc__, argv=args, version="0.1.0")
85+
86+
root = parser['SEARCHDIR']
87+
if not os.path.isdir(root):
88+
print(docopt(__doc__, "-h"))
89+
exit(1)
90+
91+
# Handle all supported odML file formats.
92+
if parser['-r']:
93+
xfiles = list(pathlib.Path(root).rglob('*.odml'))
94+
xfiles.extend(list(pathlib.Path(root).rglob('*.xml')))
95+
jfiles = list(pathlib.Path(root).rglob('*.json'))
96+
yfiles = list(pathlib.Path(root).rglob('*.yaml'))
97+
else:
98+
xfiles = list(pathlib.Path(root).glob('*.odml'))
99+
xfiles.extend(list(pathlib.Path(root).glob('*.xml')))
100+
jfiles = list(pathlib.Path(root).glob('*.json'))
101+
yfiles = list(pathlib.Path(root).glob('*.yaml'))
102+
103+
out_root = os.getcwd()
104+
if parser["-o"]:
105+
if not os.path.isdir(parser["-o"]):
106+
print("[Error] Could not find output directory '%s'" % parser["-o"])
107+
exit(1)
108+
109+
out_root = parser["-o"]
110+
111+
out_dir = tempfile.mkdtemp(prefix="odmlconv_", dir=out_root)
112+
113+
# Use this monkeypatch reporter until there is a way
114+
# to run the converters silently.
115+
report = StringIO()
116+
report.write("[Info] Files will be saved to '%s'\n" % out_dir)
117+
118+
run_conversion(xfiles, out_dir, report)
119+
run_conversion(jfiles, out_dir, report, "JSON")
120+
run_conversion(yfiles, out_dir, report, "YAML")
121+
122+
print(report.getvalue())
123+
report.close()
124+
125+
126+
if __name__ == "__main__":
127+
main(sys.argv[1:])

odml/scripts/odml_to_rdf.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
odmlToRDF searches for odML files within a provided SEARCHDIR
44
and converts them to the newest odML format version and
55
exports all found and resulting odML files to XML formatted RDF.
6-
Original files will never be overwritten.
6+
Original files will never be overwritten. New files will be
7+
written either to a new directory at the current or a specified
8+
location.
79
810
Usage: odmltordf [-r] [-o OUT] SEARCHDIR
911
@@ -14,7 +16,8 @@
1416
-o OUT Output directory. Must exist if specified.
1517
If not specified, output files will be
1618
written to the current directory.
17-
-r Search recursively.
19+
-r Search recursively. Directory structures
20+
will not be retained.
1821
-h --help Show this screen.
1922
--version Show version.
2023
"""
@@ -24,14 +27,15 @@
2427
import sys
2528
import tempfile
2629

30+
from docopt import docopt
31+
2732
try:
2833
from StringIO import StringIO
2934
except ImportError:
3035
from io import StringIO
3136

3237
import odml
3338

34-
from docopt import docopt
3539
from odml.tools.odmlparser import ODMLReader, ODMLWriter
3640
from odml.tools.version_converter import VersionConverter as VerConf
3741

setup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
with open('README.rst') as f:
2929
description_text = f.read()
3030

31-
install_req = ["lxml", "pyyaml==3.13", "rdflib", "docopt"]
31+
install_req = ["lxml", "pyyaml==3.13", "rdflib", "docopt", "pathlib"]
3232

3333
if sys.version_info < (3, 4):
3434
install_req += ["enum34"]
@@ -47,5 +47,6 @@
4747
long_description=description_text,
4848
classifiers=CLASSIFIERS,
4949
license="BSD",
50-
entry_points={'console_scripts': ['odmltordf=odml.scripts.odml_to_rdf:main']}
50+
entry_points={'console_scripts': ['odmltordf=odml.scripts.odml_to_rdf:main',
51+
'odmlconversion=odml.scripts.odml_conversion:main']}
5152
)

0 commit comments

Comments
 (0)