Ran black on sources

This commit is contained in:
Griatch 2020-04-20 09:23:44 +02:00
parent 06cb85ea6c
commit 5761a91f2f
3 changed files with 194 additions and 239 deletions

View file

@ -31,6 +31,7 @@ class _MockObj:
assert category == self.category assert category == self.category
self.dbstore[key] = value self.dbstore[key] = value
# we want to test the base traits too # we want to test the base traits too
_TEST_TRAIT_CLASS_PATHS = [ _TEST_TRAIT_CLASS_PATHS = [
"evennia.contrib.traits.Trait", "evennia.contrib.traits.Trait",
@ -39,8 +40,10 @@ _TEST_TRAIT_CLASS_PATHS = [
"evennia.contrib.traits.GaugeTrait", "evennia.contrib.traits.GaugeTrait",
] ]
class _TraitHandlerBase(TestCase): class _TraitHandlerBase(TestCase):
"Base for trait tests" "Base for trait tests"
@patch("evennia.contrib.traits._TRAIT_CLASS_PATHS", new=_TEST_TRAIT_CLASS_PATHS) @patch("evennia.contrib.traits._TRAIT_CLASS_PATHS", new=_TEST_TRAIT_CLASS_PATHS)
def setUp(self): def setUp(self):
self.obj = _MockObj() self.obj = _MockObj()
@ -48,7 +51,7 @@ class _TraitHandlerBase(TestCase):
self.obj.traits = self.traithandler self.obj.traits = self.traithandler
def _get_dbstore(self, key): def _get_dbstore(self, key):
return self.obj.dbstore['traits'][key] return self.obj.dbstore["traits"][key]
class TraitHandlerTest(_TraitHandlerBase): class TraitHandlerTest(_TraitHandlerBase):
@ -56,32 +59,18 @@ class TraitHandlerTest(_TraitHandlerBase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.traithandler.add("test1", name="Test1", trait_type="trait")
self.traithandler.add( self.traithandler.add(
"test1", "test2", name="Test2", trait_type="trait", value=["foo", {"1": [1, 2, 3]}, 4],
name="Test1",
trait_type='trait'
)
self.traithandler.add(
"test2",
name="Test2",
trait_type='trait',
value=["foo", {"1": [1, 2, 3]}, 4],
) )
def test_add_trait(self): def test_add_trait(self):
self.assertEqual( self.assertEqual(
self._get_dbstore("test1"), self._get_dbstore("test1"), {"name": "Test1", "trait_type": "trait", "value": None,}
{"name": "Test1",
"trait_type": 'trait',
"value": None,
}
) )
self.assertEqual( self.assertEqual(
self._get_dbstore("test2"), self._get_dbstore("test2"),
{"name": "Test2", {"name": "Test2", "trait_type": "trait", "value": ["foo", {"1": [1, 2, 3]}, 4],},
"trait_type": 'trait',
"value": ["foo", {"1": [1, 2, 3]}, 4],
}
) )
self.assertEqual(len(self.traithandler), 2) self.assertEqual(len(self.traithandler), 2)
@ -109,21 +98,14 @@ class TraitHandlerTest(_TraitHandlerBase):
def test_getting(self): def test_getting(self):
"Test we are getting data from the dbstore" "Test we are getting data from the dbstore"
self.assertEqual( self.assertEqual(
self.traithandler.test1._data, self.traithandler.test1._data, {"name": "Test1", "trait_type": "trait", "value": None}
{"name": "Test1", "trait_type": "trait",
"value": None}
)
self.assertEqual(
self.traithandler._cache, Something
) )
self.assertEqual(self.traithandler._cache, Something)
self.assertEqual( self.assertEqual(
self.traithandler.test2._data, self.traithandler.test2._data,
{"name": "Test2", "trait_type": "trait", {"name": "Test2", "trait_type": "trait", "value": ["foo", {"1": [1, 2, 3]}, 4]},
"value": ["foo", {"1": [1, 2, 3]}, 4]}
)
self.assertEqual(
self.traithandler._cache, Something
) )
self.assertEqual(self.traithandler._cache, Something)
self.assertFalse(self.traithandler.get("foo")) self.assertFalse(self.traithandler.get("foo"))
self.assertFalse(self.traithandler.bar) self.assertFalse(self.traithandler.bar)
@ -151,20 +133,13 @@ class TraitHandlerTest(_TraitHandlerBase):
self.assertEqual(trait.value, None) self.assertEqual(trait.value, None)
trait.value = 10 trait.value = 10
self.assertEqual(trait.value, 10) self.assertEqual(trait.value, 10)
self.assertEqual( self.assertEqual(self.obj.attributes.get("traits", category="traits")["test1"]["value"], 10)
self.obj.attributes.get("traits", category="traits")['test1']['value'],
10
)
trait.value = 20 trait.value = 20
self.assertEqual(trait.value, 20) self.assertEqual(trait.value, 20)
self.assertEqual( self.assertEqual(self.obj.attributes.get("traits", category="traits")["test1"]["value"], 20)
self.obj.attributes.get("traits", category="traits")['test1']['value'],
20
)
del trait.value del trait.value
self.assertEqual( self.assertEqual(
self.obj.attributes.get("traits", category="traits")['test1']['value'], self.obj.attributes.get("traits", category="traits")["test1"]["value"], None
None
) )
@ -188,44 +163,40 @@ class TestTrait(_TraitHandlerBase):
def test_init(self): def test_init(self):
self.assertEqual( self.assertEqual(
self.trait._data, self.trait._data,
{"name": "Test1", {
"trait_type": "trait", "name": "Test1",
"value": "value", "trait_type": "trait",
"extra_val1": "xvalue1", "value": "value",
"extra_val2": "xvalue2" "extra_val1": "xvalue1",
} "extra_val2": "xvalue2",
},
) )
def test_validate_input__valid(self): def test_validate_input__valid(self):
"""Test valid validation input""" """Test valid validation input"""
# all data supplied, and extras # all data supplied, and extras
dat = { dat = {"name": "Test", "trait_type": "trait", "value": 10, "extra_val": 1000}
"name": "Test",
"trait_type": "trait",
"value": 10,
"extra_val": 1000
}
expected = copy(dat) # we must break link or return === dat always expected = copy(dat) # we must break link or return === dat always
self.assertEqual(expected, traits.Trait.validate_input(traits.Trait, dat)) self.assertEqual(expected, traits.Trait.validate_input(traits.Trait, dat))
# don't supply value, should get default # don't supply value, should get default
dat = { dat = {
"name": "Test", "name": "Test",
"trait_type": "trait", "trait_type": "trait",
# missing value # missing value
"extra_val": 1000 "extra_val": 1000,
} }
expected = copy(dat) expected = copy(dat)
expected["value"] = traits.Trait.default_keys['value'] expected["value"] = traits.Trait.default_keys["value"]
self.assertEqual(expected, traits.Trait.validate_input(traits.Trait, dat)) self.assertEqual(expected, traits.Trait.validate_input(traits.Trait, dat))
# make sure extra values are cleaned if trait accepts no extras # make sure extra values are cleaned if trait accepts no extras
dat = { dat = {
"name": "Test", "name": "Test",
"trait_type": "trait", "trait_type": "trait",
"value": 10, "value": 10,
"extra_val1": 1000, "extra_val1": 1000,
"extra_val2": "xvalue" "extra_val2": "xvalue",
} }
expected = copy(dat) expected = copy(dat)
expected.pop("extra_val1") expected.pop("extra_val1")
@ -236,24 +207,22 @@ class TestTrait(_TraitHandlerBase):
def test_validate_input__fail(self): def test_validate_input__fail(self):
"""Test failing validation""" """Test failing validation"""
dat = { dat = {
# missing name # missing name
"trait_type": "trait", "trait_type": "trait",
"value": 10, "value": 10,
"extra_val": 1000 "extra_val": 1000,
} }
with self.assertRaises(traits.TraitException): with self.assertRaises(traits.TraitException):
traits.Trait.validate_input(traits.Trait, dat) traits.Trait.validate_input(traits.Trait, dat)
# make value a required key # make value a required key
mock_default_keys = { mock_default_keys = {"value": traits.MandatoryTraitKey}
"value": traits.MandatoryTraitKey
}
with patch.object(traits.Trait, "default_keys", mock_default_keys): with patch.object(traits.Trait, "default_keys", mock_default_keys):
dat = { dat = {
"name": "Trait", "name": "Trait",
"trait_type": "trait", "trait_type": "trait",
# missing value, now mandatory # missing value, now mandatory
"extra_val": 1000 "extra_val": 1000,
} }
with self.assertRaises(traits.TraitException): with self.assertRaises(traits.TraitException):
traits.Trait.validate_input(traits.Trait, dat) traits.Trait.validate_input(traits.Trait, dat)
@ -261,15 +230,15 @@ class TestTrait(_TraitHandlerBase):
def test_trait_getset(self): def test_trait_getset(self):
"""Get-set-del operations on trait""" """Get-set-del operations on trait"""
self.assertEqual(self.trait.name, "Test1") self.assertEqual(self.trait.name, "Test1")
self.assertEqual(self.trait['name'], "Test1") self.assertEqual(self.trait["name"], "Test1")
self.assertEqual(self.trait.value, "value") self.assertEqual(self.trait.value, "value")
self.assertEqual(self.trait['value'], "value") self.assertEqual(self.trait["value"], "value")
self.assertEqual(self.trait.extra_val1, "xvalue1" ) self.assertEqual(self.trait.extra_val1, "xvalue1")
self.assertEqual(self.trait['extra_val2'], "xvalue2") self.assertEqual(self.trait["extra_val2"], "xvalue2")
self.trait.value = 20 self.trait.value = 20
self.assertEqual(self.trait['value'], 20) self.assertEqual(self.trait["value"], 20)
self.trait['value'] = 20 self.trait["value"] = 20
self.assertEqual(self.trait.value, 20) self.assertEqual(self.trait.value, 20)
self.trait.extra_val1 = 100 self.trait.extra_val1 = 100
self.assertEqual(self.trait.extra_val1, 100) self.assertEqual(self.trait.extra_val1, 100)
@ -279,7 +248,7 @@ class TestTrait(_TraitHandlerBase):
del self.trait.foo del self.trait.foo
with self.assertRaises(KeyError): with self.assertRaises(KeyError):
self.trait['foo'] self.trait["foo"]
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
self.trait.foo self.trait.foo
del self.trait.extra_val1 del self.trait.extra_val1
@ -298,16 +267,17 @@ class TestTraitStatic(_TraitHandlerBase):
""" """
Test for static Traits Test for static Traits
""" """
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.traithandler.add( self.traithandler.add(
"test1", "test1",
name="Test1", name="Test1",
trait_type='static', trait_type="static",
base=1, base=1,
mod=2, mod=2,
extra_val1="xvalue1", extra_val1="xvalue1",
extra_val2="xvalue2" extra_val2="xvalue2",
) )
self.trait = self.traithandler.get("test1") self.trait = self.traithandler.get("test1")
@ -317,13 +287,14 @@ class TestTraitStatic(_TraitHandlerBase):
def test_init(self): def test_init(self):
self.assertEqual( self.assertEqual(
self._get_dbstore("test1"), self._get_dbstore("test1"),
{"name": "Test1", {
"trait_type": 'static', "name": "Test1",
"base": 1, "trait_type": "static",
"mod": 2, "base": 1,
"extra_val1": "xvalue1", "mod": 2,
"extra_val2": "xvalue2" "extra_val1": "xvalue1",
} "extra_val2": "xvalue2",
},
) )
def test_value(self): def test_value(self):
@ -346,53 +317,44 @@ class TestTraitCounter(_TraitHandlerBase):
""" """
Test for counter- Traits Test for counter- Traits
""" """
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.traithandler.add( self.traithandler.add(
"test1", "test1",
name="Test1", name="Test1",
trait_type='counter', trait_type="counter",
base=1, base=1,
mod=2, mod=2,
min=0, min=0,
max=10, max=10,
extra_val1="xvalue1", extra_val1="xvalue1",
extra_val2="xvalue2", extra_val2="xvalue2",
descs={ descs={0: "range0", 2: "range1", 5: "range2", 7: "range3",},
0: "range0",
2: "range1",
5: "range2",
7: "range3",
}
) )
self.trait = self.traithandler.get("test1") self.trait = self.traithandler.get("test1")
def _get_values(self): def _get_values(self):
"""Get (base, mod, value, min, max).""" """Get (base, mod, value, min, max)."""
return (self.trait.base, self.trait.mod, return (self.trait.base, self.trait.mod, self.trait.value, self.trait.min, self.trait.max)
self.trait.value, self.trait.min, self.trait.max)
def test_init(self): def test_init(self):
self.assertEqual( self.assertEqual(
self._get_dbstore("test1"), self._get_dbstore("test1"),
{"name": "Test1", {
"trait_type": 'counter', "name": "Test1",
"base": 1, "trait_type": "counter",
"mod": 2, "base": 1,
"min": 0, "mod": 2,
"max": 10, "min": 0,
"extra_val1": "xvalue1", "max": 10,
"extra_val2": "xvalue2", "extra_val1": "xvalue1",
"descs": { "extra_val2": "xvalue2",
0: "range0", "descs": {0: "range0", 2: "range1", 5: "range2", 7: "range3",},
2: "range1", "rate": 0,
5: "range2", "ratetarget": None,
7: "range3", "last_update": None,
}, },
"rate": 0,
"ratetarget": None,
"last_update": None,
}
) )
def test_value(self): def test_value(self):
@ -453,7 +415,7 @@ class TestTraitCounter(_TraitHandlerBase):
# re-activate boundaries # re-activate boundaries
self.trait.max = 15 self.trait.max = 15
self.trait.min = 10 # his is blocked since base+mod is lower self.trait.min = 10 # his is blocked since base+mod is lower
self.assertEqual(self._get_values(), (-200, 5, -195, -195, 15)) self.assertEqual(self._get_values(), (-200, 5, -195, -195, 15))
def test_boundaries__inverse(self): def test_boundaries__inverse(self):
@ -533,33 +495,34 @@ class TestTraitCounterTimed(_TraitHandlerBase):
""" """
Test for trait with timer component Test for trait with timer component
""" """
@patch("evennia.contrib.traits.time", new=MagicMock(return_value=1000)) @patch("evennia.contrib.traits.time", new=MagicMock(return_value=1000))
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.traithandler.add( self.traithandler.add(
"test1", "test1",
name="Test1", name="Test1",
trait_type='counter', trait_type="counter",
base=1, base=1,
mod=2, mod=2,
min=0, min=0,
max=100, max=100,
extra_val1="xvalue1", extra_val1="xvalue1",
extra_val2="xvalue2", extra_val2="xvalue2",
descs={ descs={0: "range0", 2: "range1", 5: "range2", 7: "range3",},
0: "range0",
2: "range1",
5: "range2",
7: "range3",
},
rate=1, rate=1,
ratetarget=None, ratetarget=None,
) )
self.trait = self.traithandler.get("test1") self.trait = self.traithandler.get("test1")
def _get_timer_data(self): def _get_timer_data(self):
return (self.trait.value, self.trait.current, self.trait.rate, return (
self.trait._data["last_update"], self.trait.ratetarget) self.trait.value,
self.trait.current,
self.trait.rate,
self.trait._data["last_update"],
self.trait.ratetarget,
)
@patch("evennia.contrib.traits.time") @patch("evennia.contrib.traits.time")
def test_timer_rate(self, mock_time): def test_timer_rate(self, mock_time):
@ -608,52 +571,42 @@ class TestTraitCounterTimed(_TraitHandlerBase):
class TestTraitGauge(_TraitHandlerBase): class TestTraitGauge(_TraitHandlerBase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.traithandler.add( self.traithandler.add(
"test1", "test1",
name="Test1", name="Test1",
trait_type='gauge', trait_type="gauge",
base=8, # max = base + mod base=8, # max = base + mod
mod=2, mod=2,
extra_val1="xvalue1", extra_val1="xvalue1",
extra_val2="xvalue2", extra_val2="xvalue2",
descs={ descs={0: "range0", 2: "range1", 5: "range2", 7: "range3",},
0: "range0",
2: "range1",
5: "range2",
7: "range3",
}
) )
self.trait = self.traithandler.get("test1") self.trait = self.traithandler.get("test1")
def _get_values(self): def _get_values(self):
"""Get (base, mod, value, min, max).""" """Get (base, mod, value, min, max)."""
return (self.trait.base, self.trait.mod, self.trait.value, return (self.trait.base, self.trait.mod, self.trait.value, self.trait.min, self.trait.max)
self.trait.min, self.trait.max)
def test_init(self): def test_init(self):
self.assertEqual( self.assertEqual(
self._get_dbstore("test1"), self._get_dbstore("test1"),
{"name": "Test1", {
"trait_type": 'gauge', "name": "Test1",
"base": 8, "trait_type": "gauge",
"mod": 2, "base": 8,
"min": 0, "mod": 2,
"extra_val1": "xvalue1", "min": 0,
"extra_val2": "xvalue2", "extra_val1": "xvalue1",
"descs": { "extra_val2": "xvalue2",
0: "range0", "descs": {0: "range0", 2: "range1", 5: "range2", 7: "range3",},
2: "range1", "rate": 0,
5: "range2", "ratetarget": None,
7: "range3", "last_update": None,
}, },
"rate": 0,
"ratetarget": None,
"last_update": None,
}
) )
def test_value(self): def test_value(self):
"""value is current, where current defaults to base + mod""" """value is current, where current defaults to base + mod"""
# current unset - follows base + mod # current unset - follows base + mod
@ -724,6 +677,7 @@ class TestTraitGauge(_TraitHandlerBase):
self.assertEqual(self._get_values(), (0, 0, 0, 0, 0)) self.assertEqual(self._get_values(), (0, 0, 0, 0, 0))
with self.assertRaises(traits.TraitException): with self.assertRaises(traits.TraitException):
del self.trait.max del self.trait.max
def test_boundaries__inverse(self): def test_boundaries__inverse(self):
"""Try to set reversed boundaries""" """Try to set reversed boundaries"""
self.trait.mod = 0 self.trait.mod = 0
@ -798,32 +752,33 @@ class TestTraitGaugeTimed(_TraitHandlerBase):
""" """
Test for trait with timer component Test for trait with timer component
""" """
@patch("evennia.contrib.traits.time", new=MagicMock(return_value=1000)) @patch("evennia.contrib.traits.time", new=MagicMock(return_value=1000))
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.traithandler.add( self.traithandler.add(
"test1", "test1",
name="Test1", name="Test1",
trait_type='gauge', trait_type="gauge",
base=98, base=98,
mod=2, mod=2,
min=0, min=0,
extra_val1="xvalue1", extra_val1="xvalue1",
extra_val2="xvalue2", extra_val2="xvalue2",
descs={ descs={0: "range0", 2: "range1", 5: "range2", 7: "range3",},
0: "range0",
2: "range1",
5: "range2",
7: "range3",
},
rate=1, rate=1,
ratetarget=None, ratetarget=None,
) )
self.trait = self.traithandler.get("test1") self.trait = self.traithandler.get("test1")
def _get_timer_data(self): def _get_timer_data(self):
return (self.trait.value, self.trait.current, self.trait.rate, return (
self.trait._data["last_update"], self.trait.ratetarget) self.trait.value,
self.trait.current,
self.trait.rate,
self.trait._data["last_update"],
self.trait.ratetarget,
)
@patch("evennia.contrib.traits.time") @patch("evennia.contrib.traits.time")
def test_timer_rate(self, mock_time): def test_timer_rate(self, mock_time):
@ -875,18 +830,11 @@ class TestTraitGaugeTimed(_TraitHandlerBase):
class TestNumericTraitOperators(TestCase): class TestNumericTraitOperators(TestCase):
"""Test case for numeric magic method implementations.""" """Test case for numeric magic method implementations."""
def setUp(self): def setUp(self):
# direct instantiation for testing only; use TraitHandler in production # direct instantiation for testing only; use TraitHandler in production
self.st = traits.Trait({ self.st = traits.Trait({"name": "Strength", "trait_type": "trait", "value": 8,})
'name': 'Strength', self.at = traits.Trait({"name": "Attack", "trait_type": "trait", "value": 4,})
'trait_type': 'trait',
'value': 8,
})
self.at = traits.Trait({
'name': 'Attack',
'trait_type': 'trait',
'value': 4,
})
def tearDown(self): def tearDown(self):
self.st, self.at = None, None self.st, self.at = None, None

View file

@ -336,8 +336,7 @@ from django.conf import settings
from functools import total_ordering from functools import total_ordering
from evennia.utils.dbserialize import _SaverDict from evennia.utils.dbserialize import _SaverDict
from evennia.utils import logger from evennia.utils import logger
from evennia.utils.utils import ( from evennia.utils.utils import inherits_from, class_from_module, list_to_string, percent
inherits_from, class_from_module, list_to_string, percent)
# Available Trait classes. # Available Trait classes.
@ -437,8 +436,7 @@ class TraitHandler:
# no existing storage; initialize it, we then have to fetch it again # no existing storage; initialize it, we then have to fetch it again
# to retain the db connection # to retain the db connection
obj.attributes.add(db_attribute_key, {}, category=db_attribute_category) obj.attributes.add(db_attribute_key, {}, category=db_attribute_category)
self.trait_data = obj.attributes.get( self.trait_data = obj.attributes.get(db_attribute_key, category=db_attribute_category)
db_attribute_key, category=db_attribute_category)
self._cache = {} self._cache = {}
def __len__(self): def __len__(self):
@ -459,8 +457,7 @@ class TraitHandler:
trait_cls = self._get_trait_class(trait_key=trait_key) trait_cls = self._get_trait_class(trait_key=trait_key)
valid_keys = list_to_string(list(trait_cls.default_keys.keys()), endsep="or") valid_keys = list_to_string(list(trait_cls.default_keys.keys()), endsep="or")
raise TraitException( raise TraitException(
"Trait object not settable directly. " "Trait object not settable directly. " f"Assign to {trait_key}.{valid_keys}."
f"Assign to {trait_key}.{valid_keys}."
) )
def __setitem__(self, trait_key, value): def __setitem__(self, trait_key, value):
@ -524,7 +521,9 @@ class TraitHandler:
trait = self._cache[trait_key] = trait_cls(_GA(self, "trait_data")[trait_key]) trait = self._cache[trait_key] = trait_cls(_GA(self, "trait_data")[trait_key])
return trait return trait
def add(self, trait_key, name=None, trait_type=DEFAULT_TRAIT_TYPE, force=True, **trait_properties): def add(
self, trait_key, name=None, trait_type=DEFAULT_TRAIT_TYPE, force=True, **trait_properties
):
""" """
Create a new Trait and add it to the handler. Create a new Trait and add it to the handler.
@ -566,7 +565,6 @@ class TraitHandler:
self.trait_data[trait_key] = trait_properties self.trait_data[trait_key] = trait_properties
def remove(self, trait_key): def remove(self, trait_key):
""" """
Remove a Trait from the handler's parent object. Remove a Trait from the handler's parent object.
@ -592,6 +590,7 @@ class TraitHandler:
# Parent Trait class # Parent Trait class
@total_ordering @total_ordering
class Trait: class Trait:
"""Represents an object or Character trait. This simple base is just """Represents an object or Character trait. This simple base is just
@ -605,6 +604,7 @@ class Trait:
value value
""" """
# this is the name used to refer to this trait when adding # this is the name used to refer to this trait when adding
# a new trait in the TraitHandler # a new trait in the TraitHandler
trait_type = "trait" trait_type = "trait"
@ -661,6 +661,7 @@ class Trait:
TraitException: If finding unset keys without a default. TraitException: If finding unset keys without a default.
""" """
def _raise_err(unset_required): def _raise_err(unset_required):
"""Helper method to format exception.""" """Helper method to format exception."""
raise TraitException( raise TraitException(
@ -668,6 +669,7 @@ class Trait:
cls.trait_type, list_to_string(list(unset_required), addquote=True) cls.trait_type, list_to_string(list(unset_required), addquote=True)
) )
) )
inp = set(trait_data.keys()) inp = set(trait_data.keys())
# separate check for name/trait_type, those are always required. # separate check for name/trait_type, those are always required.
@ -683,15 +685,13 @@ class Trait:
if MandatoryTraitKey in unset_defaults.values(): if MandatoryTraitKey in unset_defaults.values():
# we have one or more unset keys that was mandatory # we have one or more unset keys that was mandatory
_raise_err([key for key, value in unset_defaults.items() _raise_err([key for key, value in unset_defaults.items() if value == MandatoryTraitKey])
if value == MandatoryTraitKey])
# apply the default values # apply the default values
trait_data.update(unset_defaults) trait_data.update(unset_defaults)
if not cls.allow_extra_properties: if not cls.allow_extra_properties:
# don't allow any extra properties - remove the extra data # don't allow any extra properties - remove the extra data
for key in (key for key in inp.difference(req) for key in (key for key in inp.difference(req) if key not in ("name", "trait_type")):
if key not in ("name", "trait_type")):
del trait_data[key] del trait_data[key]
return trait_data return trait_data
@ -722,10 +722,8 @@ class Trait:
except KeyError: except KeyError:
raise AttributeError( raise AttributeError(
"{!r} {} ({}) has no property {!r}.".format( "{!r} {} ({}) has no property {!r}.".format(
self._data['name'], self._data["name"], type(self).__name__, self.trait_type, key
type(self).__name__, )
self.trait_type,
key)
) )
def __setattr__(self, key, value): def __setattr__(self, key, value):
@ -746,14 +744,13 @@ class Trait:
return return
else: else:
# this is some other value # this is some other value
if key in ("_data", ): if key in ("_data",):
_SA(self, key, value) _SA(self, key, value)
return return
if _GA(self, "allow_extra_properties"): if _GA(self, "allow_extra_properties"):
_GA(self, "_data")[key] = value _GA(self, "_data")[key] = value
return return
raise AttributeError(f"Can't set attribute {key} on " raise AttributeError(f"Can't set attribute {key} on " f"{self.trait_type} Trait.")
f"{self.trait_type} Trait.")
def __delattr__(self, key): def __delattr__(self, key):
""" """
@ -775,7 +772,8 @@ class Trait:
if self.default_keys[key] == MandatoryTraitKey: if self.default_keys[key] == MandatoryTraitKey:
raise TraitException( raise TraitException(
"Trait-Key {key} cannot be deleted: It's a mandatory property " "Trait-Key {key} cannot be deleted: It's a mandatory property "
"with no default value to fall back to.") "with no default value to fall back to."
)
# set to default # set to default
self._data[key] = self.default_keys[key] self._data[key] = self.default_keys[key]
elif key in self._data: elif key in self._data:
@ -797,7 +795,11 @@ class Trait:
return "{}({{{}}})".format( return "{}({{{}}})".format(
type(self).__name__, type(self).__name__,
", ".join( ", ".join(
["'{}': {!r}".format(k, self._data[k]) for k in self.default_keys if k in self._data] [
"'{}': {!r}".format(k, self._data[k])
for k in self.default_keys
if k in self._data
]
), ),
) )
@ -916,6 +918,7 @@ class Trait:
# Implementation of the respective Trait types # Implementation of the respective Trait types
class StaticTrait(Trait): class StaticTrait(Trait):
""" """
Static Trait. This is a single value with a modifier, Static Trait. This is a single value with a modifier,
@ -924,12 +927,10 @@ class StaticTrait(Trait):
value = base + mod value = base + mod
""" """
trait_type = "static" trait_type = "static"
default_keys = { default_keys = {"base": 0, "mod": 0}
"base": 0,
"mod": 0
}
def __str__(self): def __str__(self):
status = "{value:11}".format(value=self.value) status = "{value:11}".format(value=self.value)
@ -997,7 +998,7 @@ class CounterTrait(Trait):
"max": None, "max": None,
"descs": None, "descs": None,
"rate": 0, "rate": 0,
"ratetarget": None "ratetarget": None,
} }
@staticmethod @staticmethod
@ -1005,18 +1006,21 @@ class CounterTrait(Trait):
"""Add extra validation for descs""" """Add extra validation for descs"""
trait_data = Trait.validate_input(cls, trait_data) trait_data = Trait.validate_input(cls, trait_data)
# validate descs # validate descs
descs = trait_data['descs'] descs = trait_data["descs"]
if isinstance(descs, dict): if isinstance(descs, dict):
if any(not (isinstance(key, (int, float)) and isinstance(value, str)) if any(
for key, value in descs.items()): not (isinstance(key, (int, float)) and isinstance(value, str))
for key, value in descs.items()
):
raise TraitException( raise TraitException(
f"Trait descs must be defined on the " f"Trait descs must be defined on the "
f"form {{number:str}} (instead found {descs}).") f"form {{number:str}} (instead found {descs})."
)
# set up rate # set up rate
if trait_data['rate'] != 0: if trait_data["rate"] != 0:
trait_data['last_update'] = time() trait_data["last_update"] = time()
else: else:
trait_data['last_update'] = None trait_data["last_update"] = None
return trait_data return trait_data
# Helpers # Helpers
@ -1024,8 +1028,8 @@ class CounterTrait(Trait):
def _within_boundaries(self, value): def _within_boundaries(self, value):
"""Check if given value is within boundaries""" """Check if given value is within boundaries"""
return not ( return not (
(self.min is not None and value <= self.min) or (self.min is not None and value <= self.min)
(self.max is not None and value >= self.max) or (self.max is not None and value >= self.max)
) )
def _enforce_boundaries(self, value): def _enforce_boundaries(self, value):
@ -1040,32 +1044,31 @@ class CounterTrait(Trait):
def _passed_ratetarget(self, value): def _passed_ratetarget(self, value):
"""Check if we passed the ratetarget in either direction.""" """Check if we passed the ratetarget in either direction."""
ratetarget = self._data['ratetarget'] ratetarget = self._data["ratetarget"]
return (ratetarget is not None and ( return ratetarget is not None and (
(self.rate < 0 and value <= ratetarget) or (self.rate < 0 and value <= ratetarget) or (self.rate > 0 and value >= ratetarget)
(self.rate > 0 and value >= ratetarget))) )
def _stop_timer(self): def _stop_timer(self):
"""Stop rate-timer component.""" """Stop rate-timer component."""
if self.rate != 0 and self._data['last_update'] is not None: if self.rate != 0 and self._data["last_update"] is not None:
self._data['last_update'] = None self._data["last_update"] = None
def _check_and_start_timer(self, value): def _check_and_start_timer(self, value):
"""Start timer if we are not at a boundary.""" """Start timer if we are not at a boundary."""
if self.rate != 0 and self._data['last_update'] is None: if self.rate != 0 and self._data["last_update"] is None:
ratetarget = self._data['ratetarget'] ratetarget = self._data["ratetarget"]
if self._within_boundaries(value) and not self._passed_ratetarget(value): if self._within_boundaries(value) and not self._passed_ratetarget(value):
# we are not at a boundary [anymore]. # we are not at a boundary [anymore].
self._data['last_update'] = time() self._data["last_update"] = time()
return value return value
def _update_current(self, current): def _update_current(self, current):
"""Update current value by scaling with rate and time passed.""" """Update current value by scaling with rate and time passed."""
rate = self.rate rate = self.rate
if rate != 0 and self._data['last_update'] is not None: if rate != 0 and self._data["last_update"] is not None:
now = time() now = time()
tdiff = now - self._data['last_update'] tdiff = now - self._data["last_update"]
current += rate * tdiff current += rate * tdiff
value = current + self.mod value = current + self.mod
@ -1073,15 +1076,15 @@ class CounterTrait(Trait):
# even if .mod is included # even if .mod is included
if self._passed_ratetarget(value): if self._passed_ratetarget(value):
current = self._data['ratetarget'] - self.mod current = self._data["ratetarget"] - self.mod
self._stop_timer() self._stop_timer()
elif not self._within_boundaries(value): elif not self._within_boundaries(value):
current = self._enforce_boundaries(value) - self.mod current = self._enforce_boundaries(value) - self.mod
self._stop_timer() self._stop_timer()
else: else:
self._data['last_update'] = now self._data["last_update"] = now
self._data['current'] = current self._data["current"] = current
return current return current
@ -1094,7 +1097,7 @@ class CounterTrait(Trait):
@base.setter @base.setter
def base(self, value): def base(self, value):
if value is None: if value is None:
self._data["base"] = self.default_keys['base'] self._data["base"] = self.default_keys["base"]
if type(value) in (int, float): if type(value) in (int, float):
if self.min is not None and value + self.mod < self.min: if self.min is not None and value + self.mod < self.min:
value = self.min - self.mod value = self.min - self.mod
@ -1110,7 +1113,7 @@ class CounterTrait(Trait):
def mod(self, value): def mod(self, value):
if value is None: if value is None:
# unsetting the boundary to default # unsetting the boundary to default
self._data["mod"] = self.default_keys['mod'] self._data["mod"] = self.default_keys["mod"]
elif type(value) in (int, float): elif type(value) in (int, float):
if self.min is not None and value + self.base < self.min: if self.min is not None and value + self.base < self.min:
value = self.min - self.base value = self.min - self.base
@ -1168,11 +1171,11 @@ class CounterTrait(Trait):
@property @property
def ratetarget(self): def ratetarget(self):
return self._data['ratetarget'] return self._data["ratetarget"]
@ratetarget.setter @ratetarget.setter
def ratetarget(self, value): def ratetarget(self, value):
self._data['ratetarget'] = self._enforce_boundaries(value) self._data["ratetarget"] = self._enforce_boundaries(value)
self._check_and_start_timer(self.value) self._check_and_start_timer(self.value)
def percent(self, formatting="{:3.1f}%"): def percent(self, formatting="{:3.1f}%"):
@ -1268,24 +1271,24 @@ class GaugeTrait(CounterTrait):
def _update_current(self, current): def _update_current(self, current):
"""Update current value by scaling with rate and time passed.""" """Update current value by scaling with rate and time passed."""
rate = self.rate rate = self.rate
if rate != 0 and self._data['last_update'] is not None: if rate != 0 and self._data["last_update"] is not None:
now = time() now = time()
tdiff = now - self._data['last_update'] tdiff = now - self._data["last_update"]
current += rate * tdiff current += rate * tdiff
value = current value = current
# we don't worry about .mod for gauges # we don't worry about .mod for gauges
if self._passed_ratetarget(value): if self._passed_ratetarget(value):
current = self._data['ratetarget'] current = self._data["ratetarget"]
self._stop_timer() self._stop_timer()
elif not self._within_boundaries(value): elif not self._within_boundaries(value):
current = self._enforce_boundaries(value) current = self._enforce_boundaries(value)
self._stop_timer() self._stop_timer()
else: else:
self._data['last_update'] = now self._data["last_update"] = now
self._data['current'] = current self._data["current"] = current
return current return current
@ -1332,7 +1335,7 @@ class GaugeTrait(CounterTrait):
def min(self, value): def min(self, value):
"""Limit so min can never be greater than base+mod.""" """Limit so min can never be greater than base+mod."""
if value is None: if value is None:
self._data["min"] = self.default_keys['min'] self._data["min"] = self.default_keys["min"]
elif type(value) in (int, float): elif type(value) in (int, float):
self._data["min"] = min(value, self.base + self.mod) self._data["min"] = min(value, self.base + self.mod)
@ -1343,18 +1346,22 @@ class GaugeTrait(CounterTrait):
@max.setter @max.setter
def max(self, value): def max(self, value):
raise TraitException("The .max property is not settable " raise TraitException(
"on GaugeTraits. Set .base instead.") "The .max property is not settable " "on GaugeTraits. Set .base instead."
)
@max.deleter @max.deleter
def max(self): def max(self):
raise TraitException("The .max property cannot be reset " raise TraitException(
"on GaugeTraits. Reset .mod and .base instead.") "The .max property cannot be reset " "on GaugeTraits. Reset .mod and .base instead."
)
@property @property
def current(self): def current(self):
"""The `current` value of the gauge.""" """The `current` value of the gauge."""
return self._update_current(self._enforce_boundaries( return self._update_current(
self._data.get("current", self.base + self.mod))) self._enforce_boundaries(self._data.get("current", self.base + self.mod))
)
@current.setter @current.setter
def current(self, value): def current(self, value):

View file

@ -318,6 +318,7 @@ class TestPercent(TestCase):
""" """
Test the utils.percentage function. Test the utils.percentage function.
""" """
def test_ok_input(self): def test_ok_input(self):
result = utils.percent(3, 0, 10) result = utils.percent(3, 0, 10)
self.assertEqual(result, "30.0%") self.assertEqual(result, "30.0%")
@ -332,4 +333,3 @@ class TestPercent(TestCase):
self.assertEqual(utils.percent(3, 1, 1), "0.0%") self.assertEqual(utils.percent(3, 1, 1), "0.0%")
self.assertEqual(utils.percent(3, 0, 1), "100.0%") self.assertEqual(utils.percent(3, 0, 1), "100.0%")
self.assertEqual(utils.percent(-3, 0, 1), "0.0%") self.assertEqual(utils.percent(-3, 0, 1), "0.0%")