blob: ca9bd7015833307e57a9f9e5eb13fb59500a11cd [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Testing functions that use Hamilton decorators.
There are two complementary techniques here:
1. **Test the underlying callable.** Decorators such as ``@tag``,
``@parameterize`` and ``@extract_columns`` do not change what the function
*does* when you call it directly -- they change how Hamilton wires it into
the DAG. A direct call is the cheapest unit test.
2. **Test the expanded DAG.** Build a Driver, run it, and assert on the
generated nodes (e.g. ``spend_in_thousands``, ``scaled_spend``). This is the
only way to verify that the decorator wiring is correct.
"""
import decorated_functions
import pandas as pd
from hamilton import driver
def test_decorated_function_is_callable_directly() -> None:
"""`@parameterize` does not stop the function from being called directly."""
result = decorated_functions.scaled(raw_value=pd.Series([1000.0, 2000.0]), divisor=1000.0)
pd.testing.assert_series_equal(result, pd.Series([1.0, 2.0]))
def test_total_signups_ignores_tag() -> None:
"""`@tag` is metadata only -- the function still computes a sum."""
result = decorated_functions.total_signups(signups=pd.Series([1, 2, 3]))
assert result == 6
def test_parameterize_expands_into_two_nodes() -> None:
"""Build a Driver to verify `@parameterize` produced both nodes correctly."""
dr = driver.Builder().with_modules(decorated_functions).build()
inputs = {
"spend": pd.Series([1000.0, 2000.0, 3000.0]),
"signups": pd.Series([100.0, 200.0, 300.0]),
}
result = dr.execute(["spend_in_thousands", "signups_in_hundreds"], inputs=inputs)
pd.testing.assert_series_equal(
result["spend_in_thousands"], pd.Series([1.0, 2.0, 3.0]), check_names=False
)
pd.testing.assert_series_equal(
result["signups_in_hundreds"], pd.Series([1.0, 2.0, 3.0]), check_names=False
)
def test_extract_columns_exposes_each_column_as_a_node() -> None:
"""`@extract_columns` should make `scaled_spend` and `scaled_signups` queryable."""
dr = driver.Builder().with_modules(decorated_functions).build()
inputs = {
"spend": pd.Series([1000.0, 2000.0]),
"signups": pd.Series([100.0, 200.0]),
}
result = dr.execute(["scaled_spend", "scaled_signups"], inputs=inputs)
pd.testing.assert_series_equal(result["scaled_spend"], pd.Series([1.0, 2.0]), check_names=False)
pd.testing.assert_series_equal(
result["scaled_signups"], pd.Series([1.0, 2.0]), check_names=False
)