Skip to content

Commit

Permalink
Merge pull request #388 from mpsonntag/smallFixes
Browse files Browse the repository at this point in the history
Minor issue fixes and test reorganisation

LGTM
  • Loading branch information
achilleas-k authored Apr 28, 2020
2 parents 1083db4 + c6e13cf commit 266f1c1
Show file tree
Hide file tree
Showing 25 changed files with 233 additions and 147 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pip install odml
## Tutorial and examples

- We have assembled a set of
[tutorials](http://github.com/G-Node/python-odml/blob/master/doc/tutorial.rst "Python Tutorial").
[tutorials](https://python-odml.readthedocs.io/en/latest/tutorial.html "Python Tutorial").

## Python convenience scripts

Expand Down
24 changes: 22 additions & 2 deletions odml/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,29 @@
from .info import VERSION
from .tools.parser_utils import SUPPORTED_PARSERS as PARSERS

if _python_version.major < 3 or _python_version.major == 3 and _python_version.minor < 6:

def _format_warning(warn_msg, *args, **kwargs):
"""
Used to provide users with deprecation warnings via the warnings module
but without spamming them with full stack traces.
"""
final_msg = "%s\n" % str(warn_msg)
# If available add category name to the message
if args and hasattr(args[0], "__name__"):
final_msg = "%s: %s" % (args[0].__name__, final_msg)

return final_msg


# Monkey patch formatting 'warnings' messages for the whole module.
warnings.formatwarning = _format_warning

if _python_version.major < 3:
msg = "Python 2 has been deprecated.\n\todML support for Python 2 will be dropped August 2020."
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
elif _python_version.major == 3 and _python_version.minor < 6:
msg = "The '%s' package is not tested with your Python version. " % __name__
msg += "Please consider upgrading to the latest Python distribution."
msg += "\n\tPlease consider upgrading to the latest Python distribution."
warnings.warn(msg)

__version__ = VERSION
Expand Down
14 changes: 12 additions & 2 deletions odml/property.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This module provides the Base Property class.
"""
import uuid
import warnings

from . import base
from . import dtypes
Expand All @@ -12,6 +13,10 @@
from .util import format_cardinality


MSG_VALUE_DEPRECATION = "The attribute 'value' is deprecated and will be removed, " \
"use 'values' instead."


def odml_tuple_import(t_count, new_value):
"""
Checks via a heuristic if the values in a string fit the general
Expand Down Expand Up @@ -131,6 +136,8 @@ def __init__(self, name=None, values=None, parent=None, unit=None,
self._values = []
self.values = values
if not values and (value or isinstance(value, (bool, int))):
# Using stacklevel=2 to avoid file name and code line in the message output.
warnings.warn(MSG_VALUE_DEPRECATION, category=DeprecationWarning, stacklevel=2)
self.values = value

self.parent = parent
Expand Down Expand Up @@ -285,7 +292,9 @@ def value(self):
"""
Deprecated alias of 'values'. Will be removed with the next minor release.
"""
print("The attribute 'value' is deprecated. Please use 'values' instead.")
# Using stacklevel=2 to avoid file name and code line in the message output.
warnings.warn(MSG_VALUE_DEPRECATION, category=DeprecationWarning, stacklevel=2)

return self.values

@value.setter
Expand All @@ -295,7 +304,8 @@ def value(self, new_value):
:param new_value: a single value or list of values.
"""
print("The attribute 'value' is deprecated. Please use 'values' instead.")
# Using stacklevel=2 to avoid file name and code line in the message output.
warnings.warn(MSG_VALUE_DEPRECATION, category=DeprecationWarning, stacklevel=2)
self.values = new_value

def value_str(self, index=0):
Expand Down
20 changes: 16 additions & 4 deletions odml/section.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This module provides the Base Section class.
"""
import uuid
import warnings

try:
from collections.abc import Iterable
Expand Down Expand Up @@ -774,21 +775,32 @@ def reorder(self, new_index):

return self._reorder(self.parent.sections, new_index)

def create_property(self, name, value=None, dtype=None, oid=None):
def create_property(self, name, values=None, dtype=None, oid=None, value=None):
"""
Create a new property that is a child of this section.
:param name: The name of the property.
:param value: Some data value, it can be a single value or
a list of homogeneous values.
:param values: Some data value, it can be a single value or
a list of homogeneous values.
:param dtype: The data type of the values stored in the property,
if dtype is not given, the type is deduced from the values.
Check odml.DType for supported data types.
:param oid: object id, UUID string as specified in RFC 4122. If no id
is provided, an id will be generated and assigned.
:param value: Deprecated alias of 'values'. Any content of 'value' is ignored,
if 'values' is set.
:return: The new property.
"""
prop = BaseProperty(name=name, value=value, dtype=dtype, oid=oid)
if value and values:
print("Warning: Both 'values' and 'value' were set; ignoring 'value'.")

if not values and (value or isinstance(value, (bool, int))):
msg = "The attribute 'value' is deprecated and will be removed, use 'values' instead."
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
values = value

prop = BaseProperty(name=name, values=values, dtype=dtype, oid=oid)
prop.parent = self

return prop
Expand Down
3 changes: 2 additions & 1 deletion odml/tools/converters/version_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from lxml import etree as ET

from ..parser_utils import ParserException
from ..xmlparser import XML_HEADER

from ...format import Document, Section, Property
from ...info import FORMAT_VERSION
Expand Down Expand Up @@ -531,5 +532,5 @@ def write_to_file(self, filename, backend="XML"):

if data and "<odML " in data:
with open(filename, "w") as file:
file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
file.write("%s\n" % XML_HEADER)
file.write(data)
8 changes: 5 additions & 3 deletions odml/tools/version_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
This module provides backwards compatibility for the VersionConverter class.
It is deprecated and will be removed in future versions.
"""
import warnings

from .converters import VersionConverter

print("[DEPRECATION WARNING] The VersionConverter file has been moved to "
"'odml.tools.converters' and will be removed from 'odml.tools' in future "
"odML releases. Please update the imports in your code accordingly.")
_MSG = "The VersionConverter file has been moved to "\
"'odml.tools.converters' and will be removed from 'odml.tools' in future "\
"odML releases. Please update the imports in your code accordingly."
warnings.warn(_MSG, category=DeprecationWarning, stacklevel=2)
19 changes: 16 additions & 3 deletions test/test_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import os
import unittest

from glob import glob

try:
from urllib.request import pathname2url
except ImportError:
Expand All @@ -10,11 +12,23 @@
from odml import Document, Section, Property
from odml.doc import BaseDocument
from odml.dtypes import FORMAT_DATE
from .util import ODML_CACHE_DIR as CACHE_DIR, TEST_RESOURCES_DIR as RES_DIR


class TestSection(unittest.TestCase):
def setUp(self):
pass
self.local_repo_file = "local_repository_file_v1.1.xml"

def tearDown(self):
"""
Remove all files loaded to the terminology cache directory
to avoid test cross pollution.
"""
temp_file_glob = "*%s" % self.local_repo_file
find_us = os.path.join(CACHE_DIR, temp_file_glob)

for file_path in glob(find_us):
os.remove(file_path)

def test_simple_attributes(self):
author = "HPL"
Expand Down Expand Up @@ -95,8 +109,7 @@ def test_date(self):
doc.date = "some format"

def test_get_terminology_equivalent(self):
dir_path = os.path.dirname(os.path.realpath(__file__))
repo_file = os.path.join(dir_path, "resources", "local_repository_file_v1.1.xml")
repo_file = os.path.join(RES_DIR, self.local_repo_file)
local_url = "file://%s" % pathname2url(repo_file)

doc = Document(repository=local_url)
Expand Down
6 changes: 3 additions & 3 deletions test/test_doc_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@

import os
import shutil
import tempfile
import unittest

import odml
from .util import create_test_dir


class TestDocumentIntegration(unittest.TestCase):

def setUp(self):
# Set up test environment
self.tmp_dir = tempfile.mkdtemp(suffix=".odml")
self.tmp_dir = create_test_dir(__file__)

self.json_file = os.path.join(self.tmp_dir, "test.json")
self.xml_file = os.path.join(self.tmp_dir, "test.xml")
Expand All @@ -26,7 +26,7 @@ def setUp(self):
self.doc = doc

def tearDown(self):
if os.path.exists(self.tmp_dir):
if self.tmp_dir and os.path.exists(self.tmp_dir):
shutil.rmtree(self.tmp_dir)

def save_load(self):
Expand Down
6 changes: 3 additions & 3 deletions test/test_dtypes_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
import datetime as dt
import os
import shutil
import tempfile
import unittest

import odml
from .util import create_test_dir


class TestTypesIntegration(unittest.TestCase):

def setUp(self):
# Set up test environment
self.tmp_dir = tempfile.mkdtemp(suffix=".odml")
self.tmp_dir = create_test_dir(__file__)

self.json_file = os.path.join(self.tmp_dir, "test.json")
self.xml_file = os.path.join(self.tmp_dir, "test.xml")
Expand All @@ -29,7 +29,7 @@ def setUp(self):
self.doc = doc

def tearDown(self):
if os.path.exists(self.tmp_dir):
if self.tmp_dir and os.path.exists(self.tmp_dir):
shutil.rmtree(self.tmp_dir)

def test_time(self):
Expand Down
24 changes: 14 additions & 10 deletions test/test_fileio.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,44 @@
import unittest
import sys
import os
import odml
import sys
import unittest

try:
from StringIO import StringIO
except ImportError:
from io import StringIO

import odml

from .util import TEST_RESOURCES_DIR as RES_DIR


class TestTypes(unittest.TestCase):

def setUp(self):
self.dir_path = os.path.dirname(os.path.realpath(__file__))
self.file = os.path.join(self.dir_path, 'resources', 'example.odml')
self.file = os.path.join(RES_DIR, "example.odml")
# Do not allow anything to be printed on STDOUT
self.captured_stdout = StringIO()
sys.stdout = self.captured_stdout

def test_load_save(self):
doc = odml.load(self.file)
self.assertTrue(isinstance(doc, odml.doc.BaseDocument))
odml.save(doc, self.file + '_copy')
os.remove(self.file + '_copy')
file_name = "%s_copy" % self.file
odml.save(doc, file_name)
os.remove(file_name)

def test_display(self):
doc = odml.load(self.file)
odml.display(doc)

def test_invalid_parser(self):
with self.assertRaises(NotImplementedError):
odml.load(self.file, 'html')
odml.load(self.file, "html")

doc = odml.load(self.file)
with self.assertRaises(NotImplementedError):
odml.save(doc, self.file + '_copy_html', 'html')
file_name = "%s_copy_html" % self.file
odml.save(doc, file_name, "html")

with self.assertRaises(NotImplementedError):
odml.display(doc, 'html')
odml.display(doc, "html")
Loading

0 comments on commit 266f1c1

Please sign in to comment.