Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bring NominalToIntegerTransformer in line with new testing setup #261

6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ Subsections for each version can be one of the following;

Each individual change should have a link to the pull request after the description of the change.

1.3.1 (unreleased)
------------------

Changed
^^^^^^^
- Refactored NominalToIntegerTransformer tests in new format `#261 <https://github.com/lvgig/tubular/pull/261>`_

1.3.0 (2024-06-13)
------------------
Expand Down
4 changes: 2 additions & 2 deletions tests/nominal/test_BaseNominalTransformer.py
limlam96 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_not_fitted_error_raised(self, initialized_transformers):
with pytest.raises(NotFittedError):
initialized_transformers[self.transformer_name].transform(df)

def test_exception_raised(self, initialized_transformers):
def test_non_mappable_rows_exception_raised(self, initialized_transformers):
"""Test an exception is raised if non-mappable rows are present in X."""
df = d.create_df_1()

Expand All @@ -44,7 +44,7 @@ def test_exception_raised(self, initialized_transformers):

with pytest.raises(
ValueError,
match="BaseNominalTransformer: nulls would be introduced into column b from levels not present in mapping",
match=f"{self.transformer_name}: nulls would be introduced into column b from levels not present in mapping",
):
x.transform(df)

Expand Down
189 changes: 37 additions & 152 deletions tests/nominal/test_NominalToIntegerTransformer.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,37 @@
import pandas as pd
import pytest
import test_aide as ta
from test_BaseNominalTransformer import GenericBaseNominalTransformerTests

import tests.test_data as d
import tubular
from tests.base_tests import (
ColumnStrListInitTests,
GenericFitTests,
limlam96 marked this conversation as resolved.
Show resolved Hide resolved
GenericTransformTests,
OtherBaseBehaviourTests,
)
from tubular.nominal import NominalToIntegerTransformer


class TestInit:
class TestInit(ColumnStrListInitTests):
"""Tests for NominalToIntegerTransformer.init()."""

@classmethod
def setup_class(cls):
cls.transformer_name = "NominalToIntegerTransformer"

def test_start_encoding_not_int_error(self):
"""Test that an exception is raised if start_encoding is not an int."""
with pytest.raises(ValueError):
NominalToIntegerTransformer(columns="a", start_encoding="a")


class TestFit:
class TestFit(GenericFitTests):
"""Tests for NominalToIntegerTransformer.fit()."""

def test_super_fit_called(self, mocker):
"""Test that fit calls BaseTransformer.fit."""
df = d.create_df_1()

x = NominalToIntegerTransformer(columns=["a", "b"])

spy = mocker.spy(tubular.base.BaseTransformer, "fit")

x.fit(df)

assert spy.call_count == 1, "unexpected number of calls to BaseTransformer.fit"

call_args = spy.call_args_list[0]
call_pos_args = call_args[0]
call_kwargs = call_args[1]

expected_kwargs = {}

assert (
call_kwargs == expected_kwargs
), "unexpected kwargs in BaseTransformer.fit call"

expected_pos_args = (x, d.create_df_1(), None)

assert len(expected_pos_args) == len(
call_pos_args,
), "unexpected # positional args in BaseTransformer.fit call"

assert (
expected_pos_args[0] == call_pos_args[0]
), "unexpected 1st positional arg in BaseTransformer.fit call"

ta.equality.assert_equal_dispatch(
expected_pos_args[1:3],
call_pos_args[1:3],
"unexpected 2nd, 3rd positional arg in BaseTransformer.fit call",
)
@classmethod
def setup_class(cls):
cls.transformer_name = "NominalToIntegerTransformer"

def test_learnt_values(self):
"""Test that the impute values learnt during fit are expected."""
Expand All @@ -76,36 +52,14 @@ def test_learnt_values(self):
msg="mappings attribute",
)

def test_fit_returns_self(self):
"""Test fit returns self?."""
df = d.create_df_1()

x = NominalToIntegerTransformer(columns=["a", "b"])

x_fitted = x.fit(df)

assert (
x_fitted is x
), "Returned value from NominalToIntegerTransformer.fit not as expected."

def test_fit_not_changing_data(self):
"""Test fit does not change X."""
df = d.create_df_1()

x = NominalToIntegerTransformer(columns=["a", "b"])

x.fit(df)

ta.equality.assert_equal_dispatch(
expected=d.create_df_1(),
actual=df,
msg="Check X not changing during fit",
)


class TestTransform:
class TestTransform(GenericBaseNominalTransformerTests, GenericTransformTests):
"""Tests for NominalToIntegerTransformer.transform()."""

@classmethod
def setup_class(cls):
cls.transformer_name = "NominalToIntegerTransformer"

def expected_df_1():
"""Expected output for test_expected_output."""
df = pd.DataFrame(
Expand All @@ -118,55 +72,6 @@ def expected_df_1():

return df

def test_check_is_fitted_called(self, mocker):
"""Test that BaseTransformer check_is_fitted called."""
df = d.create_df_1()

x = NominalToIntegerTransformer(columns=["a", "b"])

x.fit(df)

expected_call_args = {0: {"args": (["mappings"],), "kwargs": {}}}

with ta.functions.assert_function_call(
mocker,
tubular.base.BaseTransformer,
"check_is_fitted",
expected_call_args,
):
x.transform(df)

def test_not_dataframe_error_raised(self):
df = d.create_df_1()

x = NominalToIntegerTransformer(columns=["a", "b"])
x.fit(df, df["a"])

with pytest.raises(
TypeError,
match=f"{x.classname()}: X should be a pd.DataFrame",
):
x.transform(X=[1, 2, 3, 4, 5, 6])

def test_super_transform_called(self, mocker):
"""Test that BaseNominalTransformer.transform called."""
df = d.create_df_1()

x = NominalToIntegerTransformer(columns="a")

x.fit(df)

expected_call_args = {0: {"args": (x, d.create_df_1()), "kwargs": {}}}

with ta.functions.assert_function_call(
mocker,
tubular.base.BaseTransformer,
"transform",
expected_call_args,
return_value=d.create_df_1(),
):
x.transform(df)

def test_learnt_values_not_modified(self):
limlam96 marked this conversation as resolved.
Show resolved Hide resolved
"""Test that the mappings from fit are not changed in transform."""
df = d.create_df_1()
Expand All @@ -185,22 +90,6 @@ def test_learnt_values_not_modified(self):
msg="Impute values not changed in transform",
)

def test_non_mappable_rows_raises_error(self):
"""Test that rows that cannot be mapped result in an exception."""
df = d.create_df_1()

x = NominalToIntegerTransformer(columns=["a", "b"])

x.fit(df)

df["a"] = df["a"] + 1

with pytest.raises(
ValueError,
match="NominalToIntegerTransformer: nulls would be introduced into column a from levels not present in mapping",
):
x.transform(df)

@pytest.mark.parametrize(
("df", "expected"),
ta.pandas.adjusted_dataframe_params(d.create_df_1(), expected_df_1()),
Expand All @@ -224,28 +113,12 @@ def test_expected_output(self, df, expected):
)


class TestInverseTransform:
class TestInverseTransform(GenericBaseNominalTransformerTests, GenericTransformTests):
"""Tests for NominalToIntegerTransformer.inverse_transform()."""

def test_check_is_fitted_called(self, mocker):
"""Test that BaseTransformer check_is_fitted called."""
df = d.create_df_1()

x = NominalToIntegerTransformer(columns=["a", "b"])

x.fit(df)

df_transformed = x.transform(df)

expected_call_args = {0: {"args": (["mappings"],), "kwargs": {}}}

with ta.functions.assert_function_call(
mocker,
tubular.base.BaseTransformer,
"check_is_fitted",
expected_call_args,
):
x.inverse_transform(df_transformed)
@classmethod
def setup_class(cls):
cls.transformer_name = "NominalToIntegerTransformer"

@pytest.mark.parametrize(
("df", "expected"),
Expand Down Expand Up @@ -310,3 +183,15 @@ def test_learnt_values_not_modified(self):
actual=x2.mappings,
msg="Impute values not changed in inverse_transform",
)


class TestOtherBaseBehaviour(OtherBaseBehaviourTests):
"""
Class to run tests for BaseTransformerBehaviour outside the three standard methods.

May need to overwite specific tests in this class if the tested transformer modifies this behaviour.
"""

@classmethod
def setup_class(cls):
cls.transformer_name = "NominalToIntegerTransformer"
Loading