Skip to content

Commit 1232c6c

Browse files
authored
Merge pull request #356 from mpsonntag/minorFixes
Minor fixes and cleanup LGTM
2 parents 92e5781 + f4b7202 commit 1232c6c

13 files changed

+173
-36
lines changed

MANIFEST.in

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
include LICENSE
2-
include README.rst
1+
include LICENSE README.md CHANGELOG.md
32
include odml/info.json
4-
include odml/resources/section_subclasses.yaml
5-
include odml/resources/odml-ontology.ttl
3+
recursive-include odml/resources *
4+
recursive-include test/resources *

odml/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import warnings
2+
3+
from sys import version_info as _python_version
4+
15
_property = property
26

37
from . import doc
@@ -8,6 +12,11 @@
812
from .info import VERSION
913
from .tools.parser_utils import SUPPORTED_PARSERS as PARSERS
1014

15+
if _python_version.major < 3 or _python_version.major == 3 and _python_version.minor < 6:
16+
msg = "The '%s' package is not tested with your Python version. " % __name__
17+
msg += "Please consider upgrading to the latest Python distribution."
18+
warnings.warn(msg)
19+
1120
__version__ = VERSION
1221

1322

odml/dtypes.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,12 +328,18 @@ def tuple_get(string, count=None):
328328
"""
329329
if not string:
330330
return None
331+
331332
string = string.strip()
332-
assert string.startswith("(") and string.endswith(")")
333+
if not (string.startswith("(") and string.endswith(")")):
334+
msg = "Tuple value misses brackets: '%s'" % string
335+
raise ValueError(msg)
336+
333337
string = string[1:-1]
334338
res = [x.strip() for x in string.split(";")]
335-
if count is not None: # be strict
336-
assert len(res) == count
339+
if count is not None and not len(res) == count:
340+
msg = "%s-tuple value does not match required item length" % count
341+
raise ValueError(msg)
342+
337343
return res
338344

339345

odml/property.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,38 @@
1010
from .tools.doc_inherit import inherit_docstring, allow_inherit_docstring
1111

1212

13+
def odml_tuple_import(t_count, new_value):
14+
"""
15+
Checks via a heuristic if the values in a string fit the general
16+
odml style tuple format and the individual items match the
17+
required number of tuple values.
18+
Legacy Python2 code required to parse unicode strings to a list
19+
of odml style tuples.
20+
21+
:param t_count: integer, required values within a single odml style tuple.
22+
:param new_value: string containing an odml style tuple list.
23+
:return: list of odml style tuples.
24+
"""
25+
try:
26+
unicode = unicode
27+
except NameError:
28+
unicode = str
29+
30+
if len(new_value) != 1 and not isinstance(new_value[0], unicode):
31+
return new_value
32+
33+
cln = new_value[0].strip()
34+
l_check = cln.startswith("[") and cln.endswith("]")
35+
br_check = cln.count("(") == cln.count(")")
36+
com_check = cln.count("(") == (cln.count(",") + 1)
37+
sep_check = t_count == 1 or cln.count("(") == (cln.count(";") / (t_count - 1))
38+
39+
if l_check and br_check and com_check and sep_check:
40+
new_value = cln[1:-1].split(",")
41+
42+
return new_value
43+
44+
1345
@allow_inherit_docstring
1446
class BaseProperty(base.BaseObject):
1547
"""
@@ -346,6 +378,12 @@ def values(self, new_value):
346378
if self._dtype is None:
347379
self._dtype = dtypes.infer_dtype(new_value[0])
348380

381+
# Python2 legacy code for loading odml style tuples from YAML or JSON.
382+
# Works from Python 3 onwards.
383+
if self._dtype.endswith("-tuple") and not self._validate_values(new_value):
384+
t_count = int(self._dtype.split("-")[0])
385+
new_value = odml_tuple_import(t_count, new_value)
386+
349387
if not self._validate_values(new_value):
350388
if self._dtype in ("date", "time", "datetime"):
351389
req_format = dtypes.default_values(self._dtype)

odml/tools/converters/version_converter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def _parse_json(self):
6464

6565
def _parse_yaml(self):
6666
with open(self.filename) as file:
67-
parsed_doc = yaml.load(file)
67+
parsed_doc = yaml.safe_load(file)
6868

6969
return self._parse_dict_document(parsed_doc)
7070

odml/tools/dict_parser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from .. import format as odmlfmt
77
from ..info import FORMAT_VERSION
8-
from .parser_utils import InvalidVersionException, ParserException
8+
from .parser_utils import InvalidVersionException, ParserException, odml_tuple_export
99

1010

1111
class DictWriter:
@@ -107,8 +107,8 @@ def get_properties(props_list):
107107
elif (tag == []) or tag: # Even if 'values' is empty, allow '[]'
108108
# Custom odML tuples require special handling.
109109
if attr == "values" and prop.dtype and \
110-
prop.dtype.endswith("-tuple") and len(prop.values) > 0:
111-
prop_dict["value"] = "(%s)" % ";".join(prop.values[0])
110+
prop.dtype.endswith("-tuple") and prop.values:
111+
prop_dict["value"] = odml_tuple_export(prop.values)
112112
else:
113113
# Always use the arguments key attribute name when saving
114114
prop_dict[i] = tag

odml/tools/parser_utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,24 @@ class InvalidVersionException(ParserException):
3434
Exception wrapper to indicate a non-compatible odML version.
3535
"""
3636
pass
37+
38+
39+
def odml_tuple_export(odml_tuples):
40+
"""
41+
Converts odml style tuples to a parsable string representation.
42+
Every tuple is represented by brackets '()'. The individual elements of a tuple are
43+
separated by a semicolon ';'. The individual tuples are separated by a comma ','.
44+
An odml 3-tuple list of 2 tuples would be serialized to: "[(11;12;13),(21;22;23)]".
45+
46+
:param odml_tuples: List of odml style tuples.
47+
:return: string
48+
"""
49+
str_tuples = ""
50+
for val in odml_tuples:
51+
str_val = ";".join(val)
52+
if str_tuples:
53+
str_tuples = "%s,(%s)" % (str_tuples, str_val)
54+
else:
55+
str_tuples = "(%s)" % str_val
56+
57+
return "[%s]" % str_tuples

odml/tools/rdf_converter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def load_rdf_subclasses():
4646

4747
with open(subclass_file, "r") as yaml_file:
4848
try:
49-
section_subclasses = yaml.load(yaml_file)
49+
section_subclasses = yaml.safe_load(yaml_file)
5050
except yaml.parser.ParserError as err:
5151
print("[Error] Loading RDF subclass file: %s" % err)
5252

odml/tools/xmlparser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from .. import format as ofmt
2424
from ..info import FORMAT_VERSION
25-
from .parser_utils import InvalidVersionException, ParserException
25+
from .parser_utils import InvalidVersionException, ParserException, odml_tuple_export
2626

2727
try:
2828
unicode = unicode
@@ -121,8 +121,8 @@ def save_element(curr_el):
121121
continue
122122
if isinstance(fmt, ofmt.Property.__class__) and k == "value":
123123
# Custom odML tuples require special handling for save loading from file.
124-
if curr_el.dtype and curr_el.dtype.endswith("-tuple") and len(val) > 0:
125-
ele = E(k, "(%s)" % ";".join(val[0]))
124+
if curr_el.dtype and curr_el.dtype.endswith("-tuple") and val:
125+
ele = E(k, odml_tuple_export(val))
126126
else:
127127
ele = E(k, to_csv(val))
128128
cur.append(ele)

test/test_dtypes.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
import datetime
22
import unittest
33

4+
from sys import version_info
5+
46
import odml.dtypes as typ
57

68

79
class TestTypes(unittest.TestCase):
810

11+
def assertLocalRegExp(self, text, regular_expression):
12+
"""
13+
Python 2 is dead and assertRegexpMatches is deprecated and
14+
will be removed, but keep compatibility until py 2 support is
15+
fully dropped.
16+
"""
17+
18+
if version_info.major < 3:
19+
self.assertRegexpMatches(text, regular_expression)
20+
else:
21+
self.assertRegex(text, regular_expression)
22+
923
def setUp(self):
1024
pass
1125

@@ -36,8 +50,8 @@ def test_date(self):
3650
self.assertIsInstance(typ.date_get(""), datetime.date)
3751

3852
re = "^[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1])$"
39-
self.assertRegexpMatches(typ.date_get(None).strftime(typ.FORMAT_DATE), re)
40-
self.assertRegexpMatches(typ.date_get("").strftime(typ.FORMAT_DATE), re)
53+
self.assertLocalRegExp(typ.date_get(None).strftime(typ.FORMAT_DATE), re)
54+
self.assertLocalRegExp(typ.date_get("").strftime(typ.FORMAT_DATE), re)
4155

4256
date = datetime.date(2011, 12, 1)
4357
date_string = '2011-12-01'
@@ -68,8 +82,8 @@ def test_time(self):
6882
self.assertIsInstance(typ.time_get(""), datetime.time)
6983

7084
re = "^[0-5][0-9]:[0-5][0-9]:[0-5][0-9]$"
71-
self.assertRegexpMatches(typ.time_get(None).strftime(typ.FORMAT_TIME), re)
72-
self.assertRegexpMatches(typ.time_get("").strftime(typ.FORMAT_TIME), re)
85+
self.assertLocalRegExp(typ.time_get(None).strftime(typ.FORMAT_TIME), re)
86+
self.assertLocalRegExp(typ.time_get("").strftime(typ.FORMAT_TIME), re)
7387

7488
time = datetime.time(12, 34, 56)
7589
time_string = '12:34:56'
@@ -101,8 +115,8 @@ def test_datetime(self):
101115

102116
re = "^[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1]) " \
103117
"[0-5][0-9]:[0-5][0-9]:[0-5][0-9]$"
104-
self.assertRegexpMatches(typ.datetime_get(None).strftime(typ.FORMAT_DATETIME), re)
105-
self.assertRegexpMatches(typ.datetime_get("").strftime(typ.FORMAT_DATETIME), re)
118+
self.assertLocalRegExp(typ.datetime_get(None).strftime(typ.FORMAT_DATETIME), re)
119+
self.assertLocalRegExp(typ.datetime_get("").strftime(typ.FORMAT_DATETIME), re)
106120

107121
date = datetime.datetime(2011, 12, 1, 12, 34, 56)
108122
date_string = '2011-12-01 12:34:56'
@@ -199,10 +213,10 @@ def test_tuple(self):
199213
self.assertEqual(typ.tuple_get("(39.12; 67.19)"), ["39.12", "67.19"])
200214

201215
# Test fail on missing parenthesis.
202-
with self.assertRaises(AssertionError):
216+
with self.assertRaises(ValueError):
203217
_ = typ.tuple_get("fail")
204218
# Test fail on mismatching element count and count number.
205-
with self.assertRaises(AssertionError):
219+
with self.assertRaises(ValueError):
206220
_ = typ.tuple_get("(1; 2; 3)", 2)
207221

208222
def test_dtype_none(self):

0 commit comments

Comments
 (0)