Skip to content

Commit

Permalink
Add NumberMeta for floats and ints.
Browse files Browse the repository at this point in the history
  • Loading branch information
c-mita committed Jun 16, 2016
1 parent 025aeb2 commit ac89580
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
1 change: 1 addition & 0 deletions malcolm/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Need to import these so that the register hooks are called
from malcolm.core.stringmeta import StringMeta # noqa
from malcolm.core.numbermeta import NumberMeta # noqa
40 changes: 40 additions & 0 deletions malcolm/core/numbermeta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from malcolm.core.attributemeta import AttributeMeta

from pkg_resources import require
require("numpy")
import numpy as np


_metas = {
np.int32:"malcolm:core/Int:1.0",
np.float64:"malcolm:core/Float:1.0"
}

@AttributeMeta.register_subclass(_metas[np.int32], np.int32)
@AttributeMeta.register_subclass(_metas[np.float64], np.float64)
class NumberMeta(AttributeMeta):
"""Meta object containing information for a numerical value"""

def __init__(self, name, description, dtype):
super(NumberMeta, self).__init__(name=name, description=description)
self.dtype = dtype
# TODO where and when should this be set?
self.metaOf = _metas[dtype]

def validate(self, value):
if value is None:
return None
cast = self.dtype(value)
if not isinstance(value, basestring):
assert cast == value, \
"Lost information converting %s to %s" % (value, cast)
return cast

def to_dict(self):
d = super(NumberMeta, self).to_dict()
return d

@classmethod
def from_dict(self, name, d, *args):
number_meta = NumberMeta(name, d["description"], *args)
return number_meta
60 changes: 60 additions & 0 deletions tests/test_core/test_numbermeta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import sys
import os
import unittest
from collections import OrderedDict
sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))

from pkg_resources import require
require("numpy")
import numpy as np

from malcolm.core.numbermeta import NumberMeta
from malcolm.core.attributemeta import AttributeMeta

class TestNumberMeta(unittest.TestCase):
def test_init_int(self):
nm = NumberMeta("nm", "desc", np.int32)
self.assertEqual(nm.metaOf, "malcolm:core/Int:1.0")

def test_init_float(self):
nm = NumberMeta("nm", "desc", np.float64)
self.assertEqual(nm.metaOf, "malcolm:core/Float:1.0")

def test_to_dict(self):
nm = NumberMeta("nm", "desc", np.float64)
expected = OrderedDict()
expected["description"] = "desc"
expected["metaOf"] = "malcolm:core/Float:1.0"

self.assertEqual(expected, nm.to_dict())

def test_from_dict(self):
d = {"description":"desc", "metaOf":"malcolm:core/Float:1.0"}
nm = AttributeMeta.from_dict("nm", d)
self.assertEqual(NumberMeta, type(nm))
self.assertEqual("nm", nm.name)
self.assertEqual(np.float64, nm.dtype)

class TestNumberMetaValidation(unittest.TestCase):
def test_float_against_float(self):
nm = NumberMeta("nm", "desc", np.float64)
self.assertEqual(123.456, nm.validate(123.456))

def test_int_against_float(self):
nm = NumberMeta("nm", "desc", np.float64)
self.assertEqual(123, nm.validate(123))

def test_int_against_int(self):
nm = NumberMeta("nm", "desc", np.int32)
self.assertEqual(123, nm.validate(123))

def test_float_fails_against_int(self):
nm = NumberMeta("nm", "desc", np.int32)
self.assertRaises(AssertionError, nm.validate, 123.456)

def test_none_validates(self):
nm = NumberMeta("nm", "desc", np.int32)
self.assertIsNone(nm.validate(None))

if __name__ == "__main__":
unittest.main(verbosity=2)

0 comments on commit ac89580

Please sign in to comment.