Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Object validation in separate class
Moved validation logic into eeml.validator.Validator so one can turn off these
checks using eeml.invalidator.Invalidator. Fixes #24
  • Loading branch information
petervizi committed Feb 18, 2013
1 parent b07cacb commit 6f5d804
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 32 deletions.
50 changes: 18 additions & 32 deletions eeml/__init__.py
Expand Up @@ -17,12 +17,26 @@
from eeml.namespace import EEML_SCHEMA_VERSION, SCHEMA_LOCATION
from eeml.unit import Unit
from eeml.util import _elem, _addE, _addA, _assertPosInt
from eeml.validator import Validator

validator = Validator()

def validate(validatorMethodName):
def fn(realf):
def wrapper(*args, **kwargs):
realf(*args, **kwargs)
vtor = getattr(validator, validatorMethodName)
vtor(args[0])

return wrapper
return fn

class Environment(object):
"""
The Environment element of the document.
"""

@validate('environment')
def __init__(self, title=None, feed=None, status=None, description=None,
icon=None, website=None, email=None, updated=None,
creator=None, id_=None, private=None):
Expand Down Expand Up @@ -54,26 +68,17 @@ def __init__(self, title=None, feed=None, status=None, description=None,
"""
self._title = title
self._feed = feed
if status and status not in ['frozen', 'live']:
raise ValueError("status must be either 'frozen' or 'live', "
"got {}".format(status))
self._status = status
self._description = description
self._icon = icon
self._website = website
self._email = email
self._updated = updated
self._creator = creator
_assertPosInt(id_, 'id', False)
self._id = id_
self._location = None
self._data = dict()
self._private = None
if isinstance(private, bool):
self._private = private
elif private is not None:
raise ValueError("private is expected to be bool, got {}"
.format(type(private)))
self._private = private

def setLocation(self, location):
"""
Expand Down Expand Up @@ -200,6 +205,7 @@ class Location(object):
"""
A class representing the location tag of the document.
"""
@validate('location')
def __init__(self, domain, name=None, lat=None, lon=None, ele=None,
exposure=None, disposition=None):
"""
Expand All @@ -225,20 +231,8 @@ def __init__(self, domain, name=None, lat=None, lon=None, ele=None,
self._lat = lat
self._lon = lon
self._ele = ele

if exposure is not None and exposure not in ['indoor', 'outdoor']:
raise ValueError("exposure must be 'indoor' or 'outdoor', got '{}'"
.format(exposure))
self._exposure = exposure

if domain not in ['physical', 'virtual']:
raise ValueError("domain is required, must be 'physical' or 'virtual', got '{}'"
.format(domain))
self._domain = domain

if disposition is not None and disposition not in ['fixed', 'mobile']:
raise ValueError("disposition must be 'fixed' or 'mobile', got '{}'"
.format(disposition))
self._disposition = disposition

def toeeml(self):
Expand Down Expand Up @@ -266,7 +260,7 @@ class Data(object):
"""
The Data element of the document
"""

@validate('data')
def __init__(self, id_, value, tags=list(), minValue=None, maxValue=None,
unit=None, at=None, datapoints=None):
"""
Expand All @@ -287,20 +281,13 @@ def __init__(self, id_, value, tags=list(), minValue=None, maxValue=None,
:param datapoints: additional datapoints beyond current_value
:type datapoints: `DataPoint`
"""
_assertPosInt(id_, 'id', True)
self._id = id_
self._value = value
self._tags = tags

self._minValue = minValue
self._maxValue = maxValue
if unit is not None and not isinstance(unit, Unit):
raise ValueError("unit must be an instance of Unit, got {}"
.format(type(unit)))
self._unit = unit
if at is not None and not isinstance(at, datetime):
raise ValueError("at must be an instance of datetime.datetime, "
"got {}".format(type(at)))
self._at = at
self._datapoints = datapoints

Expand Down Expand Up @@ -339,7 +326,7 @@ class DataPoints(object):
"""
The DataPoints element of the document
"""

@validate('datapoints')
def __init__(self, id_, values=list()):
"""
Create a new DataPoints. We want to be able to simply add a DataPoints
Expand All @@ -351,7 +338,6 @@ def __init__(self, id_, values=list()):
:param values: the value of the data points, pairs of (value, date), where date is optional
:type values: `float`
"""
_assertPosInt(id_, 'id', True)
self._id = id_
self._values = values

Expand Down
23 changes: 23 additions & 0 deletions eeml/invalidator.py
@@ -0,0 +1,23 @@
"""
Don't validate any input
"""


class Invalidator(object):
"""
Doesn't do much
"""

def environment(self, env):
pass

def location(self, loc):
pass

def data(self, data):
pass

def datapoints(self, datapoints):
pass

Validator = Invalidator
66 changes: 66 additions & 0 deletions eeml/validator.py
@@ -0,0 +1,66 @@
"""
Here are the validators
"""

from datetime import datetime

from eeml.unit import Unit
from eeml.util import _assertPosInt

import logging

class Version051(object):
"""
Validate constructors by version 0.5.1 specification
"""

def environment(self, env):
status = env._status
id_ = env._id
private = env._private

if status is not None and status not in ['frozen', 'live']:
raise ValueError("status must be either 'frozen' or 'live', "
"got {}".format(status))
_assertPosInt(id_, 'id', False)
if private is not None and not isinstance(private, bool):
raise ValueError("private is expected to be bool, got {}"
.format(type(private)))

def location(self, loc):
exposure = loc._exposure
domain = loc._domain
disposition = loc._disposition
# TODO validate lat and lon

if exposure is not None and exposure not in ['indoor', 'outdoor']:
raise ValueError("exposure must be 'indoor' or 'outdoor', got '{}'"
.format(exposure))

if domain not in ['physical', 'virtual']:
raise ValueError("domain is required, must be 'physical' or 'virtual', got '{}'"
.format(domain))

if disposition is not None and disposition not in ['fixed', 'mobile']:
raise ValueError("disposition must be 'fixed' or 'mobile', got '{}'"
.format(disposition))

def data(self, data):
unit = data._unit
at = data._at
id_ = data._id

_assertPosInt(id_, 'id', True)
if unit is not None and not isinstance(unit, Unit):
raise ValueError("unit must be an instance of Unit, got {}"
.format(type(unit)))
if at is not None and not isinstance(at, datetime):
raise ValueError("at must be an instance of datetime.datetime, "
"got {}".format(type(at)))

def datapoints(self, datapoints):
id_ = datapoints._id

_assertPosInt(id_, 'id', True)

Validator = Version051
8 changes: 8 additions & 0 deletions tests/test_eeml.py
Expand Up @@ -12,6 +12,7 @@
from eeml.unit import Celsius, Unit, RH

from unittest import TestCase
from unittest import main as UnitTestMain

class TestEEML(TestCase):

Expand Down Expand Up @@ -340,3 +341,10 @@ def test_multiple_update(self):
</eeml>"""),
etree.fromstring(pac.geteeml()), reporter=self.fail))

def test_invalidator(self):
import eeml.validator
oldvalidator = eeml.validator
from eeml.invalidator import Invalidator
eeml.validator = Invalidator()
env = Environment(status='foobar')
eeml.validator = oldvalidator

0 comments on commit 6f5d804

Please sign in to comment.