Skip to content

Commit

Permalink
... more coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
nickzoic committed Aug 29, 2024
1 parent 25bc7d8 commit 04da38f
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 25 deletions.
31 changes: 7 additions & 24 deletions countess/core/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,10 @@ def __init__(self, label: str, value: Optional[str] = None, choices: Optional[It
super().__init__(label, value, choices)

def get_selected_type(self):
if self.value is None:
return None
else:
try:
return self.DATA_TYPES[self.value][0]
except KeyError:
return None

def cast_value(self, value):
if value is not None:
Expand Down Expand Up @@ -530,7 +530,7 @@ def is_not_none(self):
def get_column_prefix(self):
if self.is_none():
return None
return self.value.removesuffix("*")
return super().get_column_prefix()


class ColumnOrIndexChoiceParam(ColumnChoiceParam):
Expand Down Expand Up @@ -560,7 +560,7 @@ def set_column_choices(self, choices):
self.set_choices([self.PREFIX + c for c in choices])

def get_column_name(self):
if self.value.startswith(self.PREFIX):
if type(self.value) is str and self.value.startswith(self.PREFIX):
return self.value[len(self.PREFIX) :]
return None

Expand All @@ -571,21 +571,15 @@ def get_value_from_dict(self, data: dict):
return self.value

def get_column_or_value(self, df: pd.DataFrame, numeric: bool):
if self.value.startswith(self.PREFIX):
if type(self.value) is str and self.value.startswith(self.PREFIX):
col = df[self.value[len(self.PREFIX) :]]
return col.astype("f" if numeric else "string")
else:
return float(self.value) if numeric else str(self.value)

def get_column_or_value_numeric(self, df: pd.DataFrame):
if self.value.startswith(self.PREFIX):
return df[self.value[len(self.PREFIX) :]]
else:
return self.value

def set_choices(self, choices: Iterable[str]):
self.choices = list(choices)
if self._value is not None and self._value.startswith(self.PREFIX) and self._value not in self.choices:
if self._value is not None and type(self._value) is str and self._value.startswith(self.PREFIX) and self._value not in self.choices:
self._value = self.DEFAULT_VALUE
self._choice = None

Expand Down Expand Up @@ -873,17 +867,6 @@ def copy(self) -> "MultiParam":
pp = dict(((k, p.copy()) for k, p in self.params.items()))
return self.__class__(self.label, pp)

# XXX decide if these "dict-like" accessors are worth keeping

def __getitem__(self, key):
return self.params[key]

def __contains__(self, item):
return item in self.params

def __setitem__(self, key, value):
self.params[key].value = value

def __iter__(self):
return self.params.__iter__()

Expand Down
152 changes: 151 additions & 1 deletion tests/test_parameters.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import pytest

from countess.core.parameters import BooleanParam, FloatParam, MultiParam, StringParam, make_prefix_groups
import pandas as pd

from countess.core.parameters import BooleanParam, FloatParam, MultiParam, StringParam, make_prefix_groups, ScalarParam, StringCharacterSetParam, ChoiceParam, DataTypeOrNoneChoiceParam, ColumnOrNoneChoiceParam, ColumnOrIntegerParam, DataTypeChoiceParam, ColumnChoiceParam, ColumnGroupOrNoneChoiceParam, ColumnOrIndexChoiceParam


def test_make_prefix_groups():
x = make_prefix_groups(["one_two", "one_three", "two_one", "two_two", "two_three", "three_four_five"])

assert x == {"one_": ["two", "three"], "two_": ["one", "two", "three"]}

def test_scalarparm():

sp1 = ScalarParam("x")
sp1.value = 'hello'
sp2 = sp1.copy_and_set_value('goodbye')
assert sp1.value == 'hello'
assert sp2.value == 'goodbye'

def test_stringparam():
sp = StringParam("i'm a frayed knot")
Expand Down Expand Up @@ -45,6 +54,9 @@ def test_floatparam():
assert -fp == -v
assert fp - 1 == v - 1
assert 2 - fp == 2 - v
assert float(fp) == v
assert abs(fp) == abs(v)
assert +fp == +v


def test_booleanparam():
Expand Down Expand Up @@ -77,9 +89,147 @@ def test_multiparam():

mp["foo"] = "hello"
assert mp.foo == "hello"
assert mp["foo"] == "hello"
assert 'bar' in mp

for key in mp:
assert isinstance(mp[key], StringParam)

for key, param in mp.items():
assert isinstance(param, StringParam)

mp.set_parameter('foo._label', 'fnord')
assert mp['foo'].label == 'fnord'


def test_scsp():
pp = StringCharacterSetParam('x', 'hello', character_set=set('HelO'))
pp.value = 'helicopter'
assert pp.value == 'HelOe'


def test_choiceparam():
cp = ChoiceParam('x', value='a', choices=['a','b','c','d'])

cp.value = None
assert cp.value == ''

cp.choice = 2
assert cp.choice == 2
assert cp.value == 'c'

cp.choice = 5
assert cp.choice is None
assert cp.value == ''

cp.value = 'b'
cp.set_choices(['a','b','c'])
assert cp.choice == 1
assert cp.value == 'b'

cp.set_choices(['x','y'])
assert cp.choice == 0
assert cp.value == 'x'

cp.set_choices([])
assert cp.choice is None
assert cp.value == ''


def test_dtcp1():

cp = DataTypeChoiceParam('x')
assert cp.get_selected_type() is None


def test_dtcp2():

cp = DataTypeOrNoneChoiceParam('x')

assert cp.get_selected_type() is None
assert cp.cast_value('whatever') is None
assert cp.is_none()

cp.value = 'integer'
assert cp.get_selected_type() == int
assert cp.cast_value(7.3) == 7
assert cp.cast_value('whatever') == 0
assert not cp.is_none()


def test_ccp1():

cp = ColumnChoiceParam('x', 'a')
df = pd.DataFrame([])
with pytest.raises(ValueError):
cp.get_column(df)


def test_ccp2():
df = pd.DataFrame([[1,2],[3,4]], columns=['a','b'])
cp = ColumnOrNoneChoiceParam('x')
cp.set_choices(['a','b'])
assert cp.is_none()
assert cp.get_column(df) is None

cp.value = 'a'
assert cp.is_not_none()
assert isinstance(cp.get_column(df), pd.Series)

df = df.set_index('a')
assert isinstance(cp.get_column(df), pd.Series)

df = df.reset_index().set_index(['a','b'])
assert isinstance(cp.get_column(df), pd.Series)

df = pd.DataFrame([], columns=['x','y'])
with pytest.raises(ValueError):
cp.get_column(df)

def test_coindex():
cp = ColumnOrIndexChoiceParam('x', choices=['a','b'])
df = pd.DataFrame(columns=['a','b']).set_index('a')
assert cp.is_index()
assert isinstance(cp.get_column(df), pd.Series)

cp.choice = 1
assert cp.is_not_index()
assert isinstance(cp.get_column(df), pd.Series)

def test_columnorintegerparam():
df = pd.DataFrame([[1,2],[3,4]], columns=['a','b'])
cp = ColumnOrIntegerParam('x')
cp.set_column_choices(['a','b'])

assert cp.get_column_name() is None

cp.value = '7'
assert cp.choice is None
assert cp.get_column_name() is None
assert cp.get_column_or_value(df, False) == '7'
assert cp.get_column_or_value(df, True) == 7

cp.choice = 0
assert cp.get_column_name() == 'a'
assert isinstance(cp.get_column_or_value(df, False), pd.Series)

cp.set_column_choices(['c','d'])
assert cp.choice is None

cp.value = 'hello'
assert cp.value == 0

def test_columngroup():
df = pd.DataFrame([], columns=["one_two", "one_three", "two_one", "two_two", "two_three", "three_four_five"])
cp = ColumnGroupOrNoneChoiceParam('x')
cp.set_column_choices(df.columns)
assert cp.is_none()
assert 'one_*' in cp.choices
assert 'two_*' in cp.choices
assert cp.get_column_prefix() is None

cp.choice = 2
assert cp.is_not_none()
assert cp.get_column_prefix() == 'two_'
assert cp.get_column_suffixes(df) == ['one', 'two', 'three']
assert cp.get_column_names(df) == ['two_one', 'two_two', 'two_three']

0 comments on commit 04da38f

Please sign in to comment.