2025-04-08 20:14:49 +00:00
|
|
|
import unittest
|
2025-08-05 20:46:19 +00:00
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
|
2025-04-08 20:14:49 +00:00
|
|
|
import pandas as pd
|
2025-08-05 20:46:19 +00:00
|
|
|
import pytest
|
2026-01-26 16:52:55 +00:00
|
|
|
from src.pipelines.shared.postprocessing.postprocessing_funcs import (
|
2025-10-30 15:28:39 +00:00
|
|
|
deduplicate_provider_columns,
|
2026-01-26 16:52:55 +00:00
|
|
|
flatten_singleton_string_list,
|
|
|
|
|
format_rate_fields_with_commas,
|
|
|
|
|
normalize_auto_renewal_term,
|
|
|
|
|
normalize_cpt_fields,
|
|
|
|
|
normalize_indicator_field,
|
|
|
|
|
process_patient_age_range,
|
|
|
|
|
remove_hyphens,
|
|
|
|
|
remove_redundant_reimb_info,
|
|
|
|
|
rename_columns,
|
|
|
|
|
validate_and_reformat_date,
|
|
|
|
|
)
|
2025-04-08 20:14:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestPostprocessFunctions(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
def test_normalize_indicator_field(self):
|
|
|
|
|
self.assertEqual(normalize_indicator_field("Y"), "Y")
|
|
|
|
|
self.assertEqual(normalize_indicator_field("y"), "Y")
|
|
|
|
|
self.assertEqual(normalize_indicator_field("N"), "N")
|
|
|
|
|
self.assertEqual(normalize_indicator_field(""), "N")
|
|
|
|
|
self.assertEqual(normalize_indicator_field(None), "N")
|
|
|
|
|
|
|
|
|
|
def test_format_rate_fields_with_commas(self):
|
2025-04-16 17:42:51 +00:00
|
|
|
# Test numeric values
|
2025-04-08 20:14:49 +00:00
|
|
|
self.assertEqual(format_rate_fields_with_commas("1234.567"), "1,234.57")
|
|
|
|
|
self.assertEqual(format_rate_fields_with_commas("1000"), "1,000.00")
|
2025-04-16 17:42:51 +00:00
|
|
|
self.assertEqual(format_rate_fields_with_commas(1234.567), "1,234.57")
|
|
|
|
|
self.assertEqual(format_rate_fields_with_commas(1000), "1,000.00")
|
2025-04-08 20:14:49 +00:00
|
|
|
|
|
|
|
|
def test_remove_hyphens(self):
|
|
|
|
|
self.assertEqual(remove_hyphens("123-45-6789"), "123456789")
|
|
|
|
|
self.assertEqual(remove_hyphens("123-456"), "123456")
|
|
|
|
|
self.assertEqual(remove_hyphens(None), "")
|
|
|
|
|
self.assertEqual(remove_hyphens(""), "")
|
|
|
|
|
|
|
|
|
|
def test_flatten_singleton_string_list(self):
|
|
|
|
|
self.assertEqual(flatten_singleton_string_list("['123']"), "123")
|
2025-04-16 17:42:51 +00:00
|
|
|
self.assertEqual(flatten_singleton_string_list("['123', '456']"), "123, 456")
|
2025-04-21 17:42:33 +00:00
|
|
|
self.assertEqual(flatten_singleton_string_list("11"), "11")
|
2025-04-08 20:14:49 +00:00
|
|
|
self.assertEqual(flatten_singleton_string_list("invalid"), "invalid")
|
2025-04-16 17:42:51 +00:00
|
|
|
self.assertEqual(flatten_singleton_string_list(None), "")
|
2025-04-08 20:14:49 +00:00
|
|
|
|
2025-08-04 16:10:26 +00:00
|
|
|
def test_rename_columns(self):
|
|
|
|
|
"""Tests the rename_columns function to ensure it correctly renames specified columns.
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-08-04 16:10:26 +00:00
|
|
|
Tests:
|
|
|
|
|
1. Basic column renaming from PROCEDURE_CD to CPT4_PROC_CD
|
|
|
|
|
2. Multiple columns being renamed
|
|
|
|
|
3. Handling of columns not in the rename map
|
|
|
|
|
4. Empty DataFrame
|
|
|
|
|
"""
|
|
|
|
|
# Test case 1: Basic column renaming
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df1 = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"PROCEDURE_CD": ["12345", "67890"],
|
|
|
|
|
"PROCEDURE_CD_DESC": ["Test Procedure", "Another Procedure"],
|
|
|
|
|
"OTHER_COLUMN": ["value1", "value2"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_df1 = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"CPT4_PROC_CD": ["12345", "67890"],
|
|
|
|
|
"CPT4_PROC_CD_DESC": ["Test Procedure", "Another Procedure"],
|
|
|
|
|
"OTHER_COLUMN": ["value1", "value2"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-08-04 16:10:26 +00:00
|
|
|
result_df1 = rename_columns(input_df1)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df1, expected_df1)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-08-04 16:10:26 +00:00
|
|
|
# Test case 2: Only some columns need renaming
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df2 = pd.DataFrame(
|
|
|
|
|
{"PROCEDURE_CD": ["12345", "67890"], "OTHER_COLUMN": ["value1", "value2"]}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_df2 = pd.DataFrame(
|
|
|
|
|
{"CPT4_PROC_CD": ["12345", "67890"], "OTHER_COLUMN": ["value1", "value2"]}
|
|
|
|
|
)
|
|
|
|
|
|
2025-08-04 16:10:26 +00:00
|
|
|
result_df2 = rename_columns(input_df2)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df2, expected_df2)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-08-04 16:10:26 +00:00
|
|
|
# Test case 3: None of the columns need renaming
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df3 = pd.DataFrame({"COLUMN_A": ["a", "b"], "COLUMN_B": ["c", "d"]})
|
|
|
|
|
|
2025-08-04 16:10:26 +00:00
|
|
|
result_df3 = rename_columns(input_df3)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df3, input_df3) # Should be unchanged
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-08-04 16:10:26 +00:00
|
|
|
# Test case 4: Empty DataFrame
|
|
|
|
|
empty_df = pd.DataFrame()
|
|
|
|
|
result_empty_df = rename_columns(empty_df)
|
|
|
|
|
pd.testing.assert_frame_equal(result_empty_df, empty_df) # Should be unchanged
|
|
|
|
|
|
2025-04-08 20:14:49 +00:00
|
|
|
def test_normalize_auto_renewal_term(self):
|
|
|
|
|
self.assertEqual(normalize_auto_renewal_term("12 months"), "1 year")
|
|
|
|
|
self.assertEqual(normalize_auto_renewal_term("one year"), "1 year")
|
|
|
|
|
self.assertEqual(normalize_auto_renewal_term("month to month"), "1 month")
|
|
|
|
|
self.assertEqual(normalize_auto_renewal_term("(12) 12 months"), "1 year")
|
|
|
|
|
self.assertEqual(normalize_auto_renewal_term(None), "")
|
|
|
|
|
|
|
|
|
|
def test_normalize_cpt_fields(self):
|
2025-05-13 16:58:27 +00:00
|
|
|
self.assertEqual(normalize_cpt_fields("[123, 456]"), "['123', '456']")
|
|
|
|
|
self.assertEqual(normalize_cpt_fields("123-456"), "['123-456']")
|
2025-08-05 20:46:19 +00:00
|
|
|
self.assertEqual(
|
|
|
|
|
normalize_cpt_fields("['T0000-T9999, S0000-S9999']"),
|
|
|
|
|
"['T0000-T9999', 'S0000-S9999']",
|
|
|
|
|
)
|
2025-05-13 16:58:27 +00:00
|
|
|
self.assertEqual(normalize_cpt_fields("123"), "['123']")
|
|
|
|
|
self.assertEqual(normalize_cpt_fields(None), "")
|
|
|
|
|
self.assertEqual(normalize_cpt_fields(123), "['123']")
|
|
|
|
|
|
2025-04-25 19:35:10 +00:00
|
|
|
def test_process_patient_age_range(self):
|
|
|
|
|
"""Tests the process_patient_age_range function with various age range formats.
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-04-25 19:35:10 +00:00
|
|
|
Tests:
|
|
|
|
|
1. Standard hyphenated ranges (e.g., "0-18")
|
|
|
|
|
2. Single age values
|
|
|
|
|
3. Text descriptions with "to"
|
|
|
|
|
4. Text descriptions with "and under"
|
|
|
|
|
5. Special cases like "newborn"
|
|
|
|
|
6. Empty/None values
|
|
|
|
|
7. Invalid formats
|
|
|
|
|
8. Missing PATIENT_AGE_RANGE column
|
|
|
|
|
"""
|
|
|
|
|
# Test case 1: DataFrame with PATIENT_AGE_RANGE column
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"PATIENT_AGE_RANGE": [
|
|
|
|
|
"0-18", # Standard hyphenated range
|
|
|
|
|
"21", # Single age
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-04-25 19:35:10 +00:00
|
|
|
result_df = process_patient_age_range(input_df)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-04-25 19:35:10 +00:00
|
|
|
# Verify columns
|
|
|
|
|
self.assertIn("PATIENT_AGE_MIN", result_df.columns)
|
|
|
|
|
self.assertIn("PATIENT_AGE_MAX", result_df.columns)
|
|
|
|
|
self.assertNotIn("PATIENT_AGE_RANGE", result_df.columns)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-04-25 19:35:10 +00:00
|
|
|
# Expected values
|
2025-08-05 20:46:19 +00:00
|
|
|
expected_min = ["0", "21"]
|
2025-04-25 19:35:10 +00:00
|
|
|
expected_max = ["18", "21"]
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-04-25 19:35:10 +00:00
|
|
|
# Check transformations
|
|
|
|
|
pd.testing.assert_series_equal(
|
|
|
|
|
result_df["PATIENT_AGE_MIN"],
|
|
|
|
|
pd.Series(expected_min, name="PATIENT_AGE_MIN"),
|
2025-08-05 20:46:19 +00:00
|
|
|
check_dtype=False,
|
2025-04-25 19:35:10 +00:00
|
|
|
)
|
|
|
|
|
pd.testing.assert_series_equal(
|
|
|
|
|
result_df["PATIENT_AGE_MAX"],
|
|
|
|
|
pd.Series(expected_max, name="PATIENT_AGE_MAX"),
|
2025-08-05 20:46:19 +00:00
|
|
|
check_dtype=False,
|
2025-04-25 19:35:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Test case 2: DataFrame without PATIENT_AGE_RANGE column
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df_no_age = pd.DataFrame({"OTHER_COLUMN": ["value1", "value2"]})
|
2025-04-25 19:35:10 +00:00
|
|
|
result_df_no_age = process_patient_age_range(input_df_no_age)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-04-25 19:35:10 +00:00
|
|
|
# Verify the DataFrame is unchanged
|
|
|
|
|
pd.testing.assert_frame_equal(input_df_no_age, result_df_no_age)
|
|
|
|
|
|
|
|
|
|
# Test case 3: Empty DataFrame
|
|
|
|
|
empty_df = pd.DataFrame()
|
|
|
|
|
result_empty_df = process_patient_age_range(empty_df)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-04-25 19:35:10 +00:00
|
|
|
# Verify empty DataFrame is unchanged
|
|
|
|
|
pd.testing.assert_frame_equal(empty_df, result_empty_df)
|
|
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
def test_validate_and_reformat_date(self):
|
|
|
|
|
"""Tests validate_and_reformat_date with various date formats.
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
Tests:
|
|
|
|
|
1. Date already in YYYY/MM/DD format
|
|
|
|
|
2. Common alternative formats (YYYY-MM-DD, MM/DD/YYYY, etc.)
|
|
|
|
|
3. Invalid date formats
|
|
|
|
|
4. None and non-string values
|
|
|
|
|
"""
|
|
|
|
|
# Date already in correct format
|
|
|
|
|
self.assertEqual(validate_and_reformat_date("2023/01/15"), "2023/01/15")
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
# Test various date formats that should be reformatted
|
|
|
|
|
self.assertEqual(validate_and_reformat_date("2023-01-15"), "2023/01/15")
|
|
|
|
|
self.assertEqual(validate_and_reformat_date("01/15/2023"), "2023/01/15")
|
|
|
|
|
self.assertEqual(validate_and_reformat_date("15-Jan-2023"), "2023/01/15")
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
# Test invalid formats - should return the original string
|
|
|
|
|
self.assertEqual(validate_and_reformat_date("Invalid date"), "Invalid date")
|
|
|
|
|
self.assertEqual(validate_and_reformat_date("01-15"), "01-15")
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
# Test None and non-string values
|
|
|
|
|
self.assertEqual(validate_and_reformat_date(None), None)
|
|
|
|
|
self.assertEqual(validate_and_reformat_date(12345), 12345)
|
2025-04-08 20:14:49 +00:00
|
|
|
|
2025-07-08 21:08:57 +00:00
|
|
|
def test_remove_redundant_reimb_info(self):
|
2025-07-07 16:57:47 +00:00
|
|
|
"""Tests remove_redundant_reimb_date function.
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
Tests:
|
|
|
|
|
1. When reimbursement dates match derived dates (should remove)
|
|
|
|
|
2. When reimbursement dates differ from derived dates (should keep)
|
|
|
|
|
3. When only some rows match (should remove only matching rows)
|
|
|
|
|
4. When columns are missing (should return unchanged DataFrame)
|
|
|
|
|
"""
|
|
|
|
|
# Test case 1: When dates match (should remove)
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df1 = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"REIMB_EFFECTIVE_DT": ["2023/01/01", "2023/02/01"],
|
|
|
|
|
"REIMB_TERMINATION_DT": ["2023/12/31", "2023/12/31"],
|
|
|
|
|
"AARETE_DERIVED_EFFECTIVE_DT": ["2023/01/01", "2023/02/01"],
|
|
|
|
|
"AARETE_DERIVED_TERMINATION_DT": ["2023/12/31", "2023/12/31"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_df1 = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"REIMB_EFFECTIVE_DT": ["", ""],
|
|
|
|
|
"REIMB_TERMINATION_DT": ["", ""],
|
|
|
|
|
"AARETE_DERIVED_EFFECTIVE_DT": ["2023/01/01", "2023/02/01"],
|
|
|
|
|
"AARETE_DERIVED_TERMINATION_DT": ["2023/12/31", "2023/12/31"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-08 21:08:57 +00:00
|
|
|
result_df1 = remove_redundant_reimb_info(input_df1)
|
2025-07-07 16:57:47 +00:00
|
|
|
pd.testing.assert_frame_equal(result_df1, expected_df1)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
# Test case 2: When dates differ (should keep)
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df2 = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"REIMB_EFFECTIVE_DT": ["2023/01/15", "2023/02/15"],
|
|
|
|
|
"REIMB_TERMINATION_DT": ["2023/12/15", "2023/12/15"],
|
|
|
|
|
"AARETE_DERIVED_EFFECTIVE_DT": ["2023/01/01", "2023/02/01"],
|
|
|
|
|
"AARETE_DERIVED_TERMINATION_DT": ["2023/12/31", "2023/12/31"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
# Result should be unchanged
|
2025-07-08 21:08:57 +00:00
|
|
|
result_df2 = remove_redundant_reimb_info(input_df2)
|
2025-07-07 16:57:47 +00:00
|
|
|
pd.testing.assert_frame_equal(result_df2, input_df2)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
# Test case 3: Mixed case - some match, some don't
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df3 = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"REIMB_EFFECTIVE_DT": ["2023/01/01", "2023/02/15"],
|
|
|
|
|
"REIMB_TERMINATION_DT": ["2023/12/31", "2023/12/15"],
|
|
|
|
|
"AARETE_DERIVED_EFFECTIVE_DT": ["2023/01/01", "2023/02/01"],
|
|
|
|
|
"AARETE_DERIVED_TERMINATION_DT": ["2023/12/31", "2023/12/31"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_df3 = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"REIMB_EFFECTIVE_DT": ["", "2023/02/15"],
|
|
|
|
|
"REIMB_TERMINATION_DT": ["", "2023/12/15"],
|
|
|
|
|
"AARETE_DERIVED_EFFECTIVE_DT": ["2023/01/01", "2023/02/01"],
|
|
|
|
|
"AARETE_DERIVED_TERMINATION_DT": ["2023/12/31", "2023/12/31"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-08 21:08:57 +00:00
|
|
|
result_df3 = remove_redundant_reimb_info(input_df3)
|
2025-07-07 16:57:47 +00:00
|
|
|
pd.testing.assert_frame_equal(result_df3, expected_df3)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
# Test case 4: Missing columns
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df4 = pd.DataFrame(
|
|
|
|
|
{
|
|
|
|
|
"REIMB_EFFECTIVE_DT": ["2023/01/01", "2023/02/01"],
|
|
|
|
|
"OTHER_COLUMN": ["value1", "value2"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-07 16:57:47 +00:00
|
|
|
# Result should be unchanged
|
2025-07-08 21:08:57 +00:00
|
|
|
result_df4 = remove_redundant_reimb_info(input_df4)
|
2025-07-07 16:57:47 +00:00
|
|
|
pd.testing.assert_frame_equal(result_df4, input_df4)
|
2025-04-08 20:14:49 +00:00
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
def test_deduplicate_provider_columns(self):
|
|
|
|
|
"""Tests deduplicate_provider_columns function.
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
Tests:
|
|
|
|
|
1. Basic deduplication - removes GROUP values from OTHER fields
|
|
|
|
|
2. Internal deduplication - removes duplicates within OTHER fields
|
|
|
|
|
3. Combined scenario - both GROUP removal and internal deduplication
|
|
|
|
|
4. Empty/missing values handling
|
|
|
|
|
5. Missing columns - should return unchanged DataFrame
|
|
|
|
|
6. Empty DataFrame
|
|
|
|
|
"""
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
# Test case 1: Basic GROUP removal
|
2026-02-04 15:09:44 -06:00
|
|
|
# deduplicate_provider_columns now works with lists, not pipe-delimited strings
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df1 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["123456789"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1234567890"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Main Hospital"]],
|
|
|
|
|
"PROV_OTHER_TIN": [["123456789", "987654321"]],
|
|
|
|
|
"PROV_OTHER_NPI": [["1234567890", "0987654321"]],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [["Main Hospital", "Other Clinic"]],
|
2025-08-05 20:46:19 +00:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_df1 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["123456789"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1234567890"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Main Hospital"]],
|
|
|
|
|
"PROV_OTHER_TIN": [["987654321"]],
|
|
|
|
|
"PROV_OTHER_NPI": [["0987654321"]],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [["Other Clinic"]],
|
2025-08-05 20:46:19 +00:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
result_df1 = deduplicate_provider_columns(input_df1)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df1, expected_df1)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
# Test case 2: Internal deduplication (your original example)
|
2026-02-04 15:09:44 -06:00
|
|
|
# deduplicate_provider_columns now works with lists, not pipe-delimited strings
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df2 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["061798267"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1111111111"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Group Practice"]],
|
2025-08-05 20:46:19 +00:00
|
|
|
"PROV_OTHER_TIN": [
|
2026-02-04 15:09:44 -06:00
|
|
|
[
|
|
|
|
|
"061798267",
|
|
|
|
|
"061798267",
|
|
|
|
|
"UNKNOWN",
|
|
|
|
|
"UNKNOWN",
|
|
|
|
|
"061992277",
|
|
|
|
|
"061798267",
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
"PROV_OTHER_NPI": [
|
|
|
|
|
["1111111111", "2222222222", "2222222222", "UNKNOWN"]
|
2025-08-05 20:46:19 +00:00
|
|
|
],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [
|
2026-02-04 15:09:44 -06:00
|
|
|
["Group Practice", "Other Practice", "Other Practice", "UNKNOWN"]
|
2025-08-05 20:46:19 +00:00
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_df2 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["061798267"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1111111111"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Group Practice"]],
|
|
|
|
|
"PROV_OTHER_TIN": [["061992277"]],
|
|
|
|
|
"PROV_OTHER_NPI": [["2222222222"]],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [["Other Practice"]],
|
2025-08-05 20:46:19 +00:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
result_df2 = deduplicate_provider_columns(input_df2)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df2, expected_df2)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
# Test case 3: Empty OTHER fields after deduplication
|
2026-02-04 15:09:44 -06:00
|
|
|
# deduplicate_provider_columns now works with lists, not pipe-delimited strings
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df3 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["123456789"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1234567890"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Main Hospital"]],
|
|
|
|
|
"PROV_OTHER_TIN": [["123456789", "123456789", "UNKNOWN"]],
|
|
|
|
|
"PROV_OTHER_NPI": [["1234567890", "UNKNOWN", "UNKNOWN"]],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [["Main Hospital", "UNKNOWN"]],
|
2025-08-05 20:46:19 +00:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_df3 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["123456789"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1234567890"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Main Hospital"]],
|
|
|
|
|
"PROV_OTHER_TIN": [[]],
|
|
|
|
|
"PROV_OTHER_NPI": [[]],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [[]],
|
2025-08-05 20:46:19 +00:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
result_df3 = deduplicate_provider_columns(input_df3)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df3, expected_df3)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
# Test case 4: Multiple rows
|
2026-02-04 15:09:44 -06:00
|
|
|
# deduplicate_provider_columns now works with lists, not pipe-delimited strings
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df4 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["111111111"], ["222222222"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1111111111"], ["2222222222"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Hospital A"], ["Hospital B"]],
|
2025-08-05 20:46:19 +00:00
|
|
|
"PROV_OTHER_TIN": [
|
2026-02-04 15:09:44 -06:00
|
|
|
["111111111", "333333333"],
|
|
|
|
|
["444444444", "222222222", "444444444"],
|
|
|
|
|
],
|
|
|
|
|
"PROV_OTHER_NPI": [
|
|
|
|
|
["3333333333", "1111111111"],
|
|
|
|
|
["4444444444", "2222222222"],
|
|
|
|
|
],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [
|
|
|
|
|
["Clinic C", "Hospital A"],
|
|
|
|
|
["Clinic D", "Hospital B"],
|
2025-08-05 20:46:19 +00:00
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
expected_df4 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["111111111"], ["222222222"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1111111111"], ["2222222222"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Hospital A"], ["Hospital B"]],
|
|
|
|
|
"PROV_OTHER_TIN": [["333333333"], ["444444444"]],
|
|
|
|
|
"PROV_OTHER_NPI": [["3333333333"], ["4444444444"]],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [["Clinic C"], ["Clinic D"]],
|
2025-08-05 20:46:19 +00:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
result_df4 = deduplicate_provider_columns(input_df4)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df4, expected_df4)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
# Test case 5: Missing columns - should return unchanged
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df5 = pd.DataFrame(
|
|
|
|
|
{"PROV_GROUP_TIN": ["123456789"], "OTHER_COLUMN": ["value1"]}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
result_df5 = deduplicate_provider_columns(input_df5)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df5, input_df5)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
# Test case 6: Empty DataFrame
|
|
|
|
|
empty_df = pd.DataFrame()
|
|
|
|
|
result_empty_df = deduplicate_provider_columns(empty_df)
|
|
|
|
|
pd.testing.assert_frame_equal(empty_df, result_empty_df)
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2026-02-04 15:09:44 -06:00
|
|
|
# Test case 7: Empty OTHER fields (already empty lists)
|
|
|
|
|
# deduplicate_provider_columns now works with lists, not pipe-delimited strings
|
2025-08-05 20:46:19 +00:00
|
|
|
input_df7 = pd.DataFrame(
|
|
|
|
|
{
|
2026-02-04 15:09:44 -06:00
|
|
|
"PROV_GROUP_TIN": [["123456789"]],
|
|
|
|
|
"PROV_GROUP_NPI": [["1234567890"]],
|
|
|
|
|
"PROV_GROUP_NAME_FULL": [["Main Hospital"]],
|
|
|
|
|
"PROV_OTHER_TIN": [[]],
|
|
|
|
|
"PROV_OTHER_NPI": [[]],
|
|
|
|
|
"PROV_OTHER_NAME_FULL": [[]],
|
2025-08-05 20:46:19 +00:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2025-07-18 21:59:30 +00:00
|
|
|
result_df7 = deduplicate_provider_columns(input_df7)
|
|
|
|
|
pd.testing.assert_frame_equal(result_df7, input_df7)
|
2026-01-26 16:52:55 +00:00
|
|
|
|
2025-08-05 20:46:19 +00:00
|
|
|
|
2025-04-08 20:14:49 +00:00
|
|
|
if __name__ == "__main__":
|
2025-04-14 21:51:34 +00:00
|
|
|
unittest.main()
|