Files
stack/tests/pfs/test_pipe_helpers.py
kert 16f3b43974
Some checks failed
CI / skinny-install (aco) (push) Successful in 1m12s
CI / skinny-install (api) (push) Successful in 30s
CI / skinny-install (bcda) (push) Successful in 36s
CI / skinny-install (bib) (push) Successful in 35s
CI / skinny-install (bls) (push) Successful in 27s
CI / skinny-install (ccw) (push) Successful in 32s
CI / skinny-install (cli) (push) Successful in 41s
CI / skinny-install (cms) (push) Successful in 37s
CI / skinny-install (conf) (push) Successful in 38s
CI / skinny-install (opps) (push) Successful in 33s
CI / skinny-install (perf) (push) Successful in 38s
CI / skinny-install (pfs) (push) Successful in 38s
CI / skinny-install (rex) (push) Successful in 34s
Deploy / build-scan-report (push) Failing after 46s
Infra CI / notebooks (push) Failing after 25s
Infra CI / zotero (push) Successful in 12s
Infra CI / docs (push) Failing after 16s
CI / lint-test (push) Failing after 11m2s
Infra CI / mc (push) Successful in 21s
Infra CI / api (push) Successful in 29s
Package Supply Chain / pkg-supply-chain (push) Failing after 41s
feat: full session — mail servers, comment pipeline, PRISMA fetch, email ingest
Mail: Maddy on DO (corwins.media+Resend, fhirworx.io+Postmark),
touchless/stateless/idempotent. Gitea SMTP via env_file. CMS inbox
at cmsupdates@mail.fhirworx.io with IMAP→bib poller.

Bib: regulations.gov v4 client, Federal Register discovery, 164K
comment backfill (running), IMAP email ingest, Zotero sync routing.

PRISMA: altcha PoW solver, CrossRef DOI resolution, 83/129 PDFs.
Zotero: schema parity, ops module, CLI, fail-fast guard.
CI: docs.Dockerfile COPY glob fix (tracks #341).
Infra: Gitea+marimo fhirworx themes, IOM/OIG modules.
2026-04-16 09:04:38 -04:00

875 lines
28 KiB
Python

"""Tests for pfs.pipe helper functions and readers (lines 28-547).
Covers column map dicts, Zotero discovery, Excel/CSV readers,
encoding detection, column normalization, and file type detectors.
"""
from __future__ import annotations
import sqlite3
import sys
import types
from pathlib import Path
from unittest.mock import MagicMock, patch
import polars as pl
import pytest
# ── openpyxl fake module ─────────────────────────────────────────────────────
# openpyxl is not installed in the test env, but pfs.pipe imports it lazily
# inside _find_header_row and _read_pprrvu. We inject a fake module into
# sys.modules so that `import openpyxl` succeeds and `patch()` can resolve it.
_fake_openpyxl = types.ModuleType("openpyxl")
_fake_openpyxl.load_workbook = MagicMock() # type: ignore[attr-defined]
# ── 1. Column map dicts (importing covers the lines) ────────────────────────
def test_rvu_columns_import():
from pfs.pipe import _RVU_COLUMNS
assert isinstance(_RVU_COLUMNS, dict)
assert _RVU_COLUMNS["HCPCS"] == "hcpcs"
assert _RVU_COLUMNS["WORK RVU"] == "work_rvu"
def test_gpci_columns_import():
from pfs.pipe import _GPCI_COLUMNS
assert isinstance(_GPCI_COLUMNS, dict)
assert _GPCI_COLUMNS["LOCALITY"] == "locality"
def test_labor_columns_import():
from pfs.pipe import _LABOR_COLUMNS
assert isinstance(_LABOR_COLUMNS, dict)
assert _LABOR_COLUMNS["hcpcs"] == "hcpcs"
assert _LABOR_COLUMNS["labor_code"] == "activity_code"
def test_supply_columns_import():
from pfs.pipe import _SUPPLY_COLUMNS
assert isinstance(_SUPPLY_COLUMNS, dict)
assert _SUPPLY_COLUMNS["cms_code"] == "supply_code"
def test_equipment_columns_import():
from pfs.pipe import _EQUIPMENT_COLUMNS
assert isinstance(_EQUIPMENT_COLUMNS, dict)
assert _EQUIPMENT_COLUMNS["cms_code"] == "equipment_code"
def test_work_time_columns_import():
from pfs.pipe import _WORK_TIME_COLUMNS
assert isinstance(_WORK_TIME_COLUMNS, dict)
assert _WORK_TIME_COLUMNS["cpt_code"] == "hcpcs"
# ── 2. _zotero_pfs_files ────────────────────────────────────────────────────
def _create_zotero_db(db_path: Path) -> None:
"""Create an in-memory-compatible Zotero SQLite schema at db_path."""
con = sqlite3.connect(str(db_path))
con.executescript(
"""
CREATE TABLE items (itemID INTEGER PRIMARY KEY, key TEXT);
CREATE TABLE tags (tagID INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE itemTags (itemID INTEGER, tagID INTEGER);
CREATE TABLE fields (fieldID INTEGER PRIMARY KEY, fieldName TEXT);
CREATE TABLE itemData (itemID INTEGER, fieldID INTEGER, valueID INTEGER);
CREATE TABLE itemDataValues (valueID INTEGER PRIMARY KEY, value TEXT);
CREATE TABLE itemAttachments (
itemID INTEGER, parentItemID INTEGER, path TEXT
);
"""
)
con.close()
def _populate_basic_item(
db_path: Path,
*,
item_id: int = 1,
item_key: str = "ABCD1234",
year: int = 2026,
title: str = "CY 2026 PFS Final Rule",
att_id: int = 100,
att_key: str = "STOR0001",
filename: str = "Addendum_B_2026.xlsx",
) -> None:
"""Insert a single parent item + attachment into Zotero DB."""
con = sqlite3.connect(str(db_path))
# Parent item
con.execute("INSERT INTO items VALUES (?, ?)", (item_id, item_key))
# module:pfs tag
con.execute("INSERT INTO tags VALUES (1, 'module:pfs')")
con.execute("INSERT INTO itemTags VALUES (?, 1)", (item_id,))
# year tag
con.execute("INSERT INTO tags VALUES (2, ?)", (f"year:{year}",))
con.execute("INSERT INTO itemTags VALUES (?, 2)", (item_id,))
# title field
con.execute("INSERT INTO fields VALUES (1, 'title')")
con.execute("INSERT INTO itemDataValues VALUES (1, ?)", (title,))
con.execute("INSERT INTO itemData VALUES (?, 1, 1)", (item_id,))
# Attachment item (for storage key lookup)
con.execute("INSERT INTO items VALUES (?, ?)", (att_id, att_key))
# Attachment record
con.execute(
"INSERT INTO itemAttachments VALUES (?, ?, ?)",
(att_id, item_id, f"storage:{filename}"),
)
con.commit()
con.close()
def test_zotero_pfs_files_basic(tmp_path: Path):
"""Basic discovery: one parent item with one xlsx attachment."""
from pfs.pipe import _zotero_pfs_files
db_path = tmp_path / "zotero.sqlite"
storage = tmp_path / "storage"
_create_zotero_db(db_path)
_populate_basic_item(db_path)
# Create the file on disk
file_dir = storage / "STOR0001"
file_dir.mkdir(parents=True)
(file_dir / "Addendum_B_2026.xlsx").write_bytes(b"fake")
results = _zotero_pfs_files(db_path, storage)
assert len(results) == 1
r = results[0]
assert r["item_key"] == "ABCD1234"
assert r["year"] == 2026
assert r["title"] == "CY 2026 PFS Final Rule"
assert r["filename"] == "Addendum_B_2026.xlsx"
assert r["ext"] == ".xlsx"
assert "STOR0001" in r["path"]
def test_zotero_pfs_files_macos_resource_fork_skip(tmp_path: Path):
"""Files starting with ._ (macOS resource forks) are skipped."""
from pfs.pipe import _zotero_pfs_files
db_path = tmp_path / "zotero.sqlite"
storage = tmp_path / "storage"
_create_zotero_db(db_path)
_populate_basic_item(db_path, filename="._Addendum_B.xlsx")
# Create the file on disk
file_dir = storage / "STOR0001"
file_dir.mkdir(parents=True)
(file_dir / "._Addendum_B.xlsx").write_bytes(b"fake")
results = _zotero_pfs_files(db_path, storage)
assert len(results) == 0
def test_zotero_pfs_files_missing_storage_key(tmp_path: Path):
"""Attachment whose itemID has no items row is skipped."""
from pfs.pipe import _zotero_pfs_files
db_path = tmp_path / "zotero.sqlite"
storage = tmp_path / "storage"
_create_zotero_db(db_path)
con = sqlite3.connect(str(db_path))
# Parent item
con.execute("INSERT INTO items VALUES (1, 'KEY1')")
con.execute("INSERT INTO tags VALUES (1, 'module:pfs')")
con.execute("INSERT INTO itemTags VALUES (1, 1)")
# Attachment record pointing to att_id=100, but NO items row for 100
con.execute("INSERT INTO itemAttachments VALUES (100, 1, 'storage:test.xlsx')")
con.commit()
con.close()
results = _zotero_pfs_files(db_path, storage)
assert len(results) == 0
def test_zotero_pfs_files_file_not_exists(tmp_path: Path):
"""Attachment whose file doesn't exist on disk is skipped."""
from pfs.pipe import _zotero_pfs_files
db_path = tmp_path / "zotero.sqlite"
storage = tmp_path / "storage"
_create_zotero_db(db_path)
_populate_basic_item(db_path)
# Do NOT create the file on disk
results = _zotero_pfs_files(db_path, storage)
assert len(results) == 0
def test_zotero_pfs_files_no_year_tag(tmp_path: Path):
"""Item with no year: tag gets year=0."""
from pfs.pipe import _zotero_pfs_files
db_path = tmp_path / "zotero.sqlite"
storage = tmp_path / "storage"
_create_zotero_db(db_path)
con = sqlite3.connect(str(db_path))
con.execute("INSERT INTO items VALUES (1, 'KEY1')")
con.execute("INSERT INTO tags VALUES (1, 'module:pfs')")
con.execute("INSERT INTO itemTags VALUES (1, 1)")
# No year tag — only module:pfs
# title
con.execute("INSERT INTO fields VALUES (1, 'title')")
con.execute("INSERT INTO itemDataValues VALUES (1, 'Some Title')")
con.execute("INSERT INTO itemData VALUES (1, 1, 1)")
# attachment
con.execute("INSERT INTO items VALUES (100, 'STOR0002')")
con.execute("INSERT INTO itemAttachments VALUES (100, 1, 'storage:data.csv')")
con.commit()
con.close()
file_dir = storage / "STOR0002"
file_dir.mkdir(parents=True)
(file_dir / "data.csv").write_bytes(b"a,b\n1,2\n")
results = _zotero_pfs_files(db_path, storage)
assert len(results) == 1
assert results[0]["year"] == 0
assert results[0]["title"] == "Some Title"
def test_zotero_pfs_files_no_title(tmp_path: Path):
"""Item with no title field gets empty string."""
from pfs.pipe import _zotero_pfs_files
db_path = tmp_path / "zotero.sqlite"
storage = tmp_path / "storage"
_create_zotero_db(db_path)
con = sqlite3.connect(str(db_path))
con.execute("INSERT INTO items VALUES (1, 'KEY1')")
con.execute("INSERT INTO tags VALUES (1, 'module:pfs')")
con.execute("INSERT INTO itemTags VALUES (1, 1)")
# No title data at all
# attachment
con.execute("INSERT INTO items VALUES (100, 'STOR0003')")
con.execute("INSERT INTO itemAttachments VALUES (100, 1, 'storage:data.txt')")
con.commit()
con.close()
file_dir = storage / "STOR0003"
file_dir.mkdir(parents=True)
(file_dir / "data.txt").write_bytes(b"col1\tcol2\n1\t2\n")
results = _zotero_pfs_files(db_path, storage)
assert len(results) == 1
assert results[0]["title"] == ""
assert results[0]["year"] == 0
# ── 3. _find_header_row ─────────────────────────────────────────────────────
@pytest.fixture(autouse=False)
def _inject_openpyxl():
"""Temporarily place the fake openpyxl module into sys.modules."""
prev = sys.modules.get("openpyxl")
sys.modules["openpyxl"] = _fake_openpyxl
yield
if prev is None:
sys.modules.pop("openpyxl", None)
else:
sys.modules["openpyxl"] = prev
def test_find_header_row_found(_inject_openpyxl):
"""Header row detected when a row has >= min_cols short string cells."""
from pfs.pipe import _find_header_row
mock_ws = MagicMock()
mock_ws.iter_rows.return_value = [
("Copyright 2026 CMS", None, None, None, None),
(None, None, None, None, None),
("HCPCS", "MOD", "DESC", "STATUS", "WORK RVU", "PE RVU"),
]
mock_wb = MagicMock()
mock_wb.active = mock_ws
with patch.object(_fake_openpyxl, "load_workbook", return_value=mock_wb):
result = _find_header_row("fake.xlsx", min_cols=5)
assert result == 2
mock_wb.close.assert_called_once()
def test_find_header_row_not_found(_inject_openpyxl):
"""Returns 0 when no row matches the header criteria."""
from pfs.pipe import _find_header_row
mock_ws = MagicMock()
mock_ws.iter_rows.return_value = [
(1, 2, 3, 4, 5),
(None, None, None, None, None),
]
mock_wb = MagicMock()
mock_wb.active = mock_ws
with patch.object(_fake_openpyxl, "load_workbook", return_value=mock_wb):
result = _find_header_row("fake.xlsx")
assert result == 0
mock_wb.close.assert_called_once()
# ── 4. _read_excel ──────────────────────────────────────────────────────────
def test_read_excel_auto_header():
"""_read_excel with no explicit header calls _find_header_row."""
from pfs.pipe import _read_excel
fake_df = pl.DataFrame({"a": [1]})
with (
patch("pfs.pipe._find_header_row", return_value=3) as mock_find,
patch("polars.read_excel", return_value=fake_df) as mock_read,
):
result = _read_excel("test.xlsx")
mock_find.assert_called_once_with("test.xlsx")
mock_read.assert_called_once_with("test.xlsx", read_options={"header_row": 3})
assert result.shape == (1, 1)
def test_read_excel_explicit_header():
"""_read_excel with explicit header_row skips _find_header_row."""
from pfs.pipe import _read_excel
fake_df = pl.DataFrame({"b": [2]})
with (
patch("pfs.pipe._find_header_row") as mock_find,
patch("polars.read_excel", return_value=fake_df) as mock_read,
):
result = _read_excel("test.xlsx", header_row=5)
mock_find.assert_not_called()
mock_read.assert_called_once_with("test.xlsx", read_options={"header_row": 5})
assert result.shape == (1, 1)
# ── 5. _read_pprrvu ─────────────────────────────────────────────────────────
def test_read_pprrvu_positional_rename(_inject_openpyxl):
"""PPRRVU reader does positional rename and drops internal cols."""
from pfs.pipe import _read_pprrvu
# Build a mock workbook that has HCPCS at row 5
mock_ws = MagicMock()
rows = []
for _ in range(5):
rows.append(("title row", None, None))
# Row 5: starts with HCPCS
rows.append(("HCPCS", "MOD", "DESCRIPTION"))
mock_ws.iter_rows.return_value = rows
mock_wb = MagicMock()
mock_wb.active = mock_ws
# Build a DataFrame with enough columns for positional rename
# 32 columns matching expected_order length
col_names = [f"col{i}" for i in range(32)]
data = {c: ["val"] for c in col_names}
fake_df = pl.DataFrame(data)
with (
patch.object(_fake_openpyxl, "load_workbook", return_value=mock_wb),
patch("polars.read_excel", return_value=fake_df),
):
result = _read_pprrvu("fake.xlsx")
# Internal cols (_nf_na_indicator, _f_na_indicator, _pric_ind) dropped
assert "_nf_na_indicator" not in result.columns
assert "_f_na_indicator" not in result.columns
assert "_pric_ind" not in result.columns
# Public cols present
assert "hcpcs" in result.columns
assert "mod" in result.columns
assert "description" in result.columns
def test_read_pprrvu_too_few_columns(_inject_openpyxl):
"""PPRRVU with fewer columns than expected returns df unchanged.
Real PPRRVU files are 31 (CY2015-2025) or 32 (CY2026+) columns.
Anything less triggers a warning and the original df falls through
so a later pass (_normalize_columns) can try name-based renaming.
"""
from pfs.pipe import _read_pprrvu
mock_ws = MagicMock()
mock_ws.iter_rows.return_value = [
("HCPCS", "MOD"),
]
mock_wb = MagicMock()
mock_wb.active = mock_ws
# Only 5 columns — well below the 31/32 positional minimum
fake_df = pl.DataFrame({"A": ["x"], "B": ["y"], "C": ["z"], "D": ["w"], "E": ["v"]})
with (
patch.object(_fake_openpyxl, "load_workbook", return_value=mock_wb),
patch("polars.read_excel", return_value=fake_df),
):
result = _read_pprrvu("fake.xlsx")
# No rename applied — original columns preserved
assert list(result.columns) == ["A", "B", "C", "D", "E"]
def test_read_pprrvu_no_hcpcs_row(_inject_openpyxl):
"""PPRRVU with no 'HCPCS' row uses row 0."""
from pfs.pipe import _read_pprrvu
mock_ws = MagicMock()
mock_ws.iter_rows.return_value = [
("Title", None, None),
("Other", "stuff", "here"),
]
mock_wb = MagicMock()
mock_wb.active = mock_ws
fake_df = pl.DataFrame({"A": ["x"]})
with (
patch.object(_fake_openpyxl, "load_workbook", return_value=mock_wb),
patch("polars.read_excel", return_value=fake_df) as mock_read,
):
_read_pprrvu("fake.xlsx")
# hcpcs_row stays 0 since no row starts with "HCPCS". Reader now
# pins engine='calamine' because xlsx2csv silently ignored
# read_options['header_row'] and returned a single-column title
# DataFrame — see pfs.pipe._read_pprrvu docstring.
mock_read.assert_called_once_with(
"fake.xlsx",
engine="calamine",
read_options={"header_row": 0},
)
# ── 6. _read_csv_with_header ────────────────────────────────────────────────
def test_read_csv_with_header_skips_title_rows(tmp_path: Path):
"""Title rows before the actual header are skipped."""
from pfs.pipe import _read_csv_with_header
csv_file = tmp_path / "rvu.csv"
csv_file.write_text(
"CY 2026 Physician Fee Schedule\n"
"Published January 2026\n"
"HCPCS,MOD,DESCRIPTION,STATUS,WORK_RVU\n"
"99213, ,Office Visit,A,0.97\n"
"99214, ,Office Visit,A,1.50\n",
encoding="utf-8",
)
result = _read_csv_with_header(str(csv_file))
assert "HCPCS" in result.columns
assert result.shape[0] == 2
def test_read_csv_with_header_no_valid_header(tmp_path: Path):
"""When no row looks like a header, i falls through to 0."""
from pfs.pipe import _read_csv_with_header
csv_file = tmp_path / "numbers.csv"
# All rows have only numeric or empty cells — no alpha
csv_file.write_text(
"1,2,3\n4,5,6\n7,8,9\n",
encoding="utf-8",
)
result = _read_csv_with_header(str(csv_file))
# Falls through to i=0, reads from start
assert result.shape[0] >= 2
# ── 7. _detect_encoding ─────────────────────────────────────────────────────
def test_detect_encoding_utf16_le(tmp_path: Path):
from pfs.pipe import _detect_encoding
f = tmp_path / "le.txt"
f.write_bytes(b"\xff\xfe" + "hello".encode("utf-16-le"))
assert _detect_encoding(str(f)) == "utf-16"
def test_detect_encoding_utf16_be(tmp_path: Path):
from pfs.pipe import _detect_encoding
f = tmp_path / "be.txt"
f.write_bytes(b"\xfe\xff" + "hello".encode("utf-16-be"))
assert _detect_encoding(str(f)) == "utf-16"
def test_detect_encoding_utf8(tmp_path: Path):
from pfs.pipe import _detect_encoding
f = tmp_path / "utf8.txt"
f.write_bytes(b"hello world")
assert _detect_encoding(str(f)) == "utf-8-sig"
# ── 8. _read_tsv ────────────────────────────────────────────────────────────
def test_read_tsv_basic(tmp_path: Path):
from pfs.pipe import _read_tsv
tsv = tmp_path / "data.txt"
tsv.write_text(
"Title line ignored\n"
"HCPCS\tMOD\tDESCRIPTION\tSTATUS\n"
"99213\t\tOffice Visit\tA\n"
"99214\t\tOffice Visit\tA\n",
encoding="utf-8",
)
result = _read_tsv(str(tsv))
assert "HCPCS" in result.columns
assert result.shape[0] == 2
def test_read_tsv_utf16(tmp_path: Path):
"""UTF-16 LE encoded TSV is handled correctly."""
from pfs.pipe import _read_tsv
content = "Title line\nCOL_A\tCOL_B\tCOL_C\nval1\tval2\tval3\n"
tsv = tmp_path / "utf16.txt"
tsv.write_bytes(content.encode("utf-16"))
result = _read_tsv(str(tsv))
# Should find header and parse
assert result.shape[0] >= 1
def test_read_tsv_no_title_rows(tmp_path: Path):
"""TSV where the first row IS the header."""
from pfs.pipe import _read_tsv
tsv = tmp_path / "clean.txt"
tsv.write_text(
"ALPHA\tBETA\tGAMMA\n1\t2\t3\n",
encoding="utf-8",
)
result = _read_tsv(str(tsv))
assert "ALPHA" in result.columns
assert result.shape[0] == 1
# ── 9. _normalize_columns ───────────────────────────────────────────────────
def test_normalize_columns_rename():
"""Columns are renamed via case-insensitive lookup."""
from pfs.pipe import _normalize_columns
df = pl.DataFrame({"HCPCS": ["99213"], "MOD": [""], "DESCRIPTION": ["x"]})
col_map = {"HCPCS": "hcpcs", "MOD": "mod", "DESCRIPTION": "description"}
result = _normalize_columns(df, col_map)
assert list(result.columns) == ["hcpcs", "mod", "description"]
def test_normalize_columns_drops_unmapped():
"""Columns not in the map are dropped."""
from pfs.pipe import _normalize_columns
df = pl.DataFrame({"HCPCS": ["99213"], "EXTRA_COL": ["x"], "MOD": [""]})
col_map = {"HCPCS": "hcpcs", "MOD": "mod"}
result = _normalize_columns(df, col_map)
assert "EXTRA_COL" not in result.columns
assert list(result.columns) == ["hcpcs", "mod"]
def test_normalize_columns_internal_col_dropped():
"""Columns mapped to _internal names are renamed then dropped."""
from pfs.pipe import _normalize_columns
df = pl.DataFrame({"hcpcs": ["99213"], "source": ["cms"], "global_period": ["10"]})
col_map = {
"hcpcs": "hcpcs",
"source": "_source",
"global_period": "_global_period",
}
result = _normalize_columns(df, col_map)
assert "_source" not in result.columns
assert "_global_period" not in result.columns
assert "hcpcs" in result.columns
def test_normalize_columns_no_matches():
"""When no columns match, returns original df unchanged."""
from pfs.pipe import _normalize_columns
df = pl.DataFrame({"UNKNOWN_A": [1], "UNKNOWN_B": [2]})
col_map = {"HCPCS": "hcpcs"}
result = _normalize_columns(df, col_map)
# No matches → keep is empty → returns df as-is
assert list(result.columns) == ["UNKNOWN_A", "UNKNOWN_B"]
def test_normalize_columns_newline_normalization():
"""Column names with embedded newlines are normalized before lookup."""
from pfs.pipe import _normalize_columns
df = pl.DataFrame({"WORK\nRVU": [0.97], "MP\nRVU": [0.07]})
col_map = {"WORK RVU": "work_rvu", "MP RVU": "mp_rvu"}
result = _normalize_columns(df, col_map)
assert "work_rvu" in result.columns
assert "mp_rvu" in result.columns
def test_normalize_columns_case_insensitive():
"""Lookup is case-insensitive."""
from pfs.pipe import _normalize_columns
df = pl.DataFrame({"hcpcs": ["99213"], "mod": [""]})
col_map = {"HCPCS": "hcpcs", "MOD": "mod"}
result = _normalize_columns(df, col_map)
assert list(result.columns) == ["hcpcs", "mod"]
# ── 10. File type detectors ─────────────────────────────────────────────────
class TestIsAddendumB:
def test_addendum_b_space(self):
from pfs.pipe import _is_addendum_b
assert _is_addendum_b("Addendum B 2026.xlsx") is True
def test_addendum_b_underscore(self):
from pfs.pipe import _is_addendum_b
assert _is_addendum_b("Addendum_B_2026.xlsx") is True
def test_addendum_b_startswith(self):
from pfs.pipe import _is_addendum_b
assert _is_addendum_b("ADDENDUM_B2026.xlsx") is True
def test_not_addendum_b(self):
from pfs.pipe import _is_addendum_b
assert _is_addendum_b("Addendum_E_2026.xlsx") is False
def test_not_addendum_at_all(self):
from pfs.pipe import _is_addendum_b
assert _is_addendum_b("GPCI_2026.xlsx") is False
class TestIsPprrvu:
def test_pprrvu(self):
from pfs.pipe import _is_pprrvu
assert _is_pprrvu("PPRRVU26A.xlsx") is True
def test_not_pprrvu(self):
from pfs.pipe import _is_pprrvu
assert _is_pprrvu("RVU26A.csv") is False
def test_pprrvu_lowercase(self):
from pfs.pipe import _is_pprrvu
assert _is_pprrvu("pprrvu26b.xlsx") is True
class TestIsGpciFile:
def test_gpci(self):
from pfs.pipe import _is_gpci_file
assert _is_gpci_file("GPCI_2026.csv") is True
def test_addendum_e_space(self):
from pfs.pipe import _is_gpci_file
assert _is_gpci_file("Addendum E 2026.xlsx") is True
def test_addendum_e_end_of_string(self):
from pfs.pipe import _is_gpci_file
assert _is_gpci_file("Addendum_E.xlsx") is True
def test_gpci_but_addendum_b(self):
from pfs.pipe import _is_gpci_file
assert _is_gpci_file("GPCI ADDENDUM B 2026.xlsx") is False
def test_not_gpci(self):
from pfs.pipe import _is_gpci_file
assert _is_gpci_file("RVU_2026.csv") is False
class TestIsPufLabor:
def test_puf_labor(self):
from pfs.pipe import _is_puf_labor
assert _is_puf_labor("PUF_LABOR_2026.csv") is True
def test_puf_labor_task_excluded(self):
from pfs.pipe import _is_puf_labor
assert _is_puf_labor("PUF_LABOR_TASK_2026.csv") is False
def test_puf_labor_old_excluded(self):
from pfs.pipe import _is_puf_labor
assert _is_puf_labor("PUF_LABOR_OLD.csv") is False
def test_not_puf_labor(self):
from pfs.pipe import _is_puf_labor
assert _is_puf_labor("PUF_SUPPLY.csv") is False
class TestIsPufSupply:
def test_puf_supply(self):
from pfs.pipe import _is_puf_supply
assert _is_puf_supply("PUF_SUPPLY_2026.csv") is True
def test_not_puf_supply(self):
from pfs.pipe import _is_puf_supply
assert _is_puf_supply("PUF_LABOR.csv") is False
class TestIsPufEquip:
def test_puf_equip(self):
from pfs.pipe import _is_puf_equip
assert _is_puf_equip("PUF_EQUIP_2026.csv") is True
def test_puf_equipment(self):
from pfs.pipe import _is_puf_equip
assert _is_puf_equip("PUF_EQUIPMENT_2026.csv") is True
def test_not_puf_equip(self):
from pfs.pipe import _is_puf_equip
assert _is_puf_equip("PUF_LABOR.csv") is False
class TestIsWorkTime:
def test_work_time_underscore(self):
from pfs.pipe import _is_work_time
assert _is_work_time("WORK_TIME_2026.csv") is True
def test_work_time_space(self):
from pfs.pipe import _is_work_time
assert _is_work_time("Work Time 2026.csv") is True
def test_phystime(self):
from pfs.pipe import _is_work_time
assert _is_work_time("PHYSTIME2026.csv") is True
def test_not_work_time(self):
from pfs.pipe import _is_work_time
assert _is_work_time("RVU_2026.csv") is False
class TestIsCarrierFile:
def test_pfall(self):
from pfs.pipe import _is_carrier_file
assert _is_carrier_file("PFALL26.TXT") is True
def test_per_state_2_letters(self):
from pfs.pipe import _is_carrier_file
assert _is_carrier_file("PFNY26R.TXT") is True
def test_per_state_3_letters(self):
from pfs.pipe import _is_carrier_file
assert _is_carrier_file("PFPRV26.TXT") is True
def test_not_carrier(self):
from pfs.pipe import _is_carrier_file
assert _is_carrier_file("RVU26.TXT") is False
def test_not_txt(self):
from pfs.pipe import _is_carrier_file
assert _is_carrier_file("PFALL26.CSV") is False
def test_pf_one_letter(self):
"""PF with only 1 state letter does not match."""
from pfs.pipe import _is_carrier_file
assert _is_carrier_file("PFA26.TXT") is False
class TestIsZipCarrierFile:
def test_zip5(self):
from pfs.pipe import _is_zip_carrier_file
assert _is_zip_carrier_file("ZIP5_2026.TXT") is True
def test_zip5_layout_excluded(self):
from pfs.pipe import _is_zip_carrier_file
assert _is_zip_carrier_file("ZIP5_LYOUT.TXT") is False
def test_not_zip5(self):
from pfs.pipe import _is_zip_carrier_file
assert _is_zip_carrier_file("PFALL26.TXT") is False
def test_zip5_csv_not_matched(self):
from pfs.pipe import _is_zip_carrier_file
assert _is_zip_carrier_file("ZIP5_2026.CSV") is False
class TestExtractYearFromTitle:
def test_cy_year(self):
from pfs.pipe import _extract_year_from_title
assert _extract_year_from_title("CY 2026 PFS Final Rule") == 2026
def test_cy_no_space(self):
from pfs.pipe import _extract_year_from_title
assert _extract_year_from_title("CY2025 PFS Proposed") == 2025
def test_no_match(self):
from pfs.pipe import _extract_year_from_title
assert _extract_year_from_title("Physician Fee Schedule") is None
class TestIsFinalRule:
def test_final_capitalized(self):
from pfs.pipe import _is_final_rule
assert _is_final_rule("CY 2026 PFS Final Rule") is True
def test_final_lowercase(self):
from pfs.pipe import _is_final_rule
assert _is_final_rule("CY 2026 PFS final rule") is True
def test_proposed(self):
from pfs.pipe import _is_final_rule
assert _is_final_rule("CY 2026 PFS Proposed Rule") is False