Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ autofix_report_enriched.json
# CI artifacts (uploaded/stored elsewhere; never commit)
/coverage.json
/pytest-junit.xml
/.coverage*

# Python runtime/build artifacts
__pycache__/
Expand Down
7 changes: 6 additions & 1 deletion scripts/build_runner_workbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,12 @@ def _control_data_sheet_xml(month_values: list[str]) -> str:


def _settings_sheet_xml() -> str:
rows = ['<row r="1">' + _inline_str_cell("A1", "Setting") + _inline_str_cell("B1", "Value") + "</row>"]
rows = [
'<row r="1">'
+ _inline_str_cell("A1", "Setting")
+ _inline_str_cell("B1", "Value")
+ "</row>"
]
for index, (label, value) in enumerate(_SETTINGS_ROWS, start=2):
rows.append(
'<row r="{row}">{label_cell}{value_cell}</row>'.format(
Expand Down
4 changes: 3 additions & 1 deletion src/counter_risk/chat/providers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ def build_provider_model_registry(
class LangChainProviderClient:
"""LangChain-backed provider client with ordered provider fallbacks."""

def __init__(self, *, provider_chain: tuple[str, ...], required_env_keys: tuple[str, ...]) -> None:
def __init__(
self, *, provider_chain: tuple[str, ...], required_env_keys: tuple[str, ...]
) -> None:
self._provider_chain = provider_chain
self._required_env_keys = required_env_keys

Expand Down
8 changes: 3 additions & 5 deletions src/counter_risk/chat/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ def _visible_provider_models() -> dict[str, set[str]]:
if _offline_mode_enabled():
return _PROVIDER_MODELS
return {
provider: models
for provider, models in _PROVIDER_MODELS.items()
if provider != "local"
provider: models for provider, models in _PROVIDER_MODELS.items() if provider != "local"
}


Expand Down Expand Up @@ -85,6 +83,7 @@ def _default_model_key() -> str:
return models[0]
return _PLACEHOLDER_MODEL


_INJECTION_PATTERNS: Final[tuple[re.Pattern[str], ...]] = (
re.compile(r"ignore\s+(all\s+)?(previous|prior)\s+instructions", re.IGNORECASE),
re.compile(r"disregard\s+(the\s+)?(rules|instructions)", re.IGNORECASE),
Expand Down Expand Up @@ -358,8 +357,7 @@ def get_provider_models() -> dict[str, tuple[str, ...]]:
"""Return provider/model catalog for UI and validation surfaces."""

return {
provider: tuple(sorted(models))
for provider, models in _visible_provider_models().items()
provider: tuple(sorted(models)) for provider, models in _visible_provider_models().items()
}


Expand Down
12 changes: 5 additions & 7 deletions src/counter_risk/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,7 @@ def _run_with_discovery(args: argparse.Namespace) -> int:
return 0


def _resolve_discovery_as_of_date(
*, config: WorkflowConfig, as_of_date: str | None
) -> date | None:
def _resolve_discovery_as_of_date(*, config: WorkflowConfig, as_of_date: str | None) -> date | None:
if as_of_date:
return date.fromisoformat(as_of_date.strip())
return config.as_of_date
Expand Down Expand Up @@ -321,7 +319,9 @@ def _runner_settings_enable_discovery(settings: dict[str, str]) -> bool:
return settings.get(_SETTINGS_DISCOVERY_MODE_KEY, "").strip().casefold() == "discover"


def _load_config_with_runner_settings(config_path: Path, settings: dict[str, str]) -> WorkflowConfig:
def _load_config_with_runner_settings(
config_path: Path, settings: dict[str, str]
) -> WorkflowConfig:
config = load_config(config_path)
overrides: dict[str, Any] = {}

Expand All @@ -335,9 +335,7 @@ def _load_config_with_runner_settings(config_path: Path, settings: dict[str, str
configured_roots = dict(config.input_discovery.directory_roots)
if configured_roots:
overrides["input_discovery"] = config.input_discovery.model_copy(
update={
"directory_roots": dict.fromkeys(sorted(configured_roots), input_root_path)
}
update={"directory_roots": dict.fromkeys(sorted(configured_roots), input_root_path)}
)
else:
overrides["input_discovery"] = config.input_discovery.model_copy(
Expand Down
8 changes: 2 additions & 6 deletions src/counter_risk/mosers/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,9 @@ def resolve_marker_bound_range(
) -> MarkerBoundRange:
"""Resolve inclusive row bounds by locating *start_marker* and *end_marker*."""

start_row = find_row_containing_text(
worksheet, start_marker, min_row=min_row, max_row=max_row
)
start_row = find_row_containing_text(worksheet, start_marker, min_row=min_row, max_row=max_row)
if start_row is None:
raise ValueError(
f"Unable to locate marker {start_marker!r} in sheet {worksheet.title!r}."
)
raise ValueError(f"Unable to locate marker {start_marker!r} in sheet {worksheet.title!r}.")
end_row = find_row_containing_text(
worksheet,
end_marker,
Expand Down
12 changes: 7 additions & 5 deletions src/counter_risk/parsers/repo_cash_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ def _load_xlsx_rows(path: Path) -> list[dict[str, str]]:
def _rows_to_repo_cash_mapping(rows: list[dict[str, str]], *, path: Path) -> dict[str, float]:
if not rows:
return {}
normalized_rows = [{_normalize_header(key): value for key, value in row.items()} for row in rows]
normalized_rows = [
{_normalize_header(key): value for key, value in row.items()} for row in rows
]
header_names = {key for row in normalized_rows for key in row}
counterparty_header = _first_matching_header(header_names, _COUNTERPARTY_HEADER_ALIASES)
cash_header = _first_matching_header(header_names, _CASH_HEADER_ALIASES)
Expand All @@ -157,17 +159,17 @@ def _rows_to_repo_cash_mapping(rows: list[dict[str, str]], *, path: Path) -> dic
if not raw_cash:
continue
canonical_counterparty = normalize_counterparty(raw_counterparty)
mapping[canonical_counterparty] = _coerce_cash_value(raw_cash, path=path, row_index=row_index)
mapping[canonical_counterparty] = _coerce_cash_value(
raw_cash, path=path, row_index=row_index
)
return mapping


def _normalize_header(value: str) -> str:
return value.strip().casefold().replace(" ", "_")


def _first_matching_header(
headers: set[str], candidates: tuple[str, ...]
) -> str | None:
def _first_matching_header(headers: set[str], candidates: tuple[str, ...]) -> str | None:
for candidate in candidates:
if candidate in headers:
return candidate
Expand Down
14 changes: 11 additions & 3 deletions src/counter_risk/pipeline/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -1145,11 +1145,17 @@ def _load_repo_cash_by_counterparty(
warnings.append(f"Repo Cash overrides file present but empty: {overrides_path}")

required_counterparties = sorted(
{normalize_counterparty(value) for value in config.required_repo_counterparties if value.strip()},
{
normalize_counterparty(value)
for value in config.required_repo_counterparties
if value.strip()
},
key=str.casefold,
)
missing_required = [
counterparty for counterparty in required_counterparties if counterparty not in repo_cash_by_counterparty
counterparty
for counterparty in required_counterparties
if counterparty not in repo_cash_by_counterparty
]
if missing_required:
_handle_repo_cash_condition(
Expand Down Expand Up @@ -2194,7 +2200,9 @@ def _derive_dropin_output_filename(template_path: Path) -> str:
return f"{stem}-filled.xlsx"


def _build_dropin_notional_breakdown(totals_records: Sequence[Mapping[str, Any]]) -> dict[str, float]:
def _build_dropin_notional_breakdown(
totals_records: Sequence[Mapping[str, Any]],
) -> dict[str, float]:
class_totals = dict.fromkeys(_CLASS_BREAKDOWN_COLUMNS, 0.0)
total_notional = 0.0

Expand Down
4 changes: 3 additions & 1 deletion src/counter_risk/runner_launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ def resolve_output_dir(repo_root: str, selected_date: str, output_root: str = "r
return f"{resolve_output_root(repo_root, output_root)}\\{parsed_date.isoformat()}_000000"


def resolve_data_quality_summary_path(repo_root: str, selected_date: str, output_root: str = "runs") -> str:
def resolve_data_quality_summary_path(
repo_root: str, selected_date: str, output_root: str = "runs"
) -> str:
return f"{resolve_output_dir(repo_root, selected_date, output_root)}\\{_DATA_QUALITY_SUMMARY_FILENAME}"


Expand Down
6 changes: 3 additions & 3 deletions src/counter_risk/writers/historical_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,9 +707,9 @@ def append_wal_row(
columns=tuple(range(1, preserve_through_column + 1)),
)

worksheet.cell(
row=append_target.append_row, column=append_target.date_column
).value = px_date
worksheet.cell(row=append_target.append_row, column=append_target.date_column).value = (
px_date
)
worksheet.cell(row=append_target.append_row, column=append_target.wal_column).value = float(
wal_value
)
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/test_cli_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ def _run_cli(*, repo_root: Path, args: list[str]) -> subprocess.CompletedProcess
env = os.environ.copy()
src_path = str(repo_root / "src")
existing_pythonpath = env.get("PYTHONPATH", "")
env["PYTHONPATH"] = src_path if not existing_pythonpath else f"{src_path}{os.pathsep}{existing_pythonpath}"
env["PYTHONPATH"] = (
src_path if not existing_pythonpath else f"{src_path}{os.pathsep}{existing_pythonpath}"
)
return subprocess.run(
[sys.executable, "-m", "counter_risk.cli", *args],
cwd=repo_root,
Expand Down
30 changes: 15 additions & 15 deletions tests/spec/test_macro_spec_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ def test_macro_spec_doc_exists() -> None:

def test_macro_spec_doc_lists_runnerlaunch_macro_intents() -> None:
content = MACRO_SPEC_PATH.read_text(encoding="utf-8")
assert "Macro Intent (Plain Language)" in content, (
"docs/macro_spec.md must include a plain-language macro intent section."
)
assert (
"Macro Intent (Plain Language)" in content
), "docs/macro_spec.md must include a plain-language macro intent section."

for macro_name in EXPECTED_MACROS:
assert f"`{macro_name}`" in content, (
Expand All @@ -32,9 +32,9 @@ def test_macro_spec_doc_lists_runnerlaunch_macro_intents() -> None:

def test_macro_spec_doc_lists_required_inputs_and_output_expectations_per_macro() -> None:
content = MACRO_SPEC_PATH.read_text(encoding="utf-8")
assert "Per-Macro Requirements" in content, (
"docs/macro_spec.md must include a per-macro requirements section."
)
assert (
"Per-Macro Requirements" in content
), "docs/macro_spec.md must include a per-macro requirements section."

required_section_markers = (
"Required inputs (sheet names, columns):",
Expand Down Expand Up @@ -65,12 +65,12 @@ def test_macro_spec_doc_lists_required_inputs_and_output_expectations_per_macro(

def test_macro_spec_doc_includes_known_acceptable_drift_section() -> None:
content = MACRO_SPEC_PATH.read_text(encoding="utf-8")
assert "Known-Acceptable Drift" in content, (
"docs/macro_spec.md must document known-acceptable drift."
)
assert "rel_tol=1e-12" in content and "abs_tol=1e-12" in content, (
"Known-acceptable drift must include explicit numeric tolerances."
)
assert "rounding" in content.lower(), (
"Known-acceptable drift must include explicit rounding guidance."
)
assert (
"Known-Acceptable Drift" in content
), "docs/macro_spec.md must document known-acceptable drift."
assert (
"rel_tol=1e-12" in content and "abs_tol=1e-12" in content
), "Known-acceptable drift must include explicit numeric tolerances."
assert (
"rounding" in content.lower()
), "Known-acceptable drift must include explicit rounding guidance."
18 changes: 9 additions & 9 deletions tests/spec/test_macro_spec_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@

def test_macro_spec_fixture_inputs_exist(macro_spec_cases: tuple[Any, ...]) -> None:
for case in macro_spec_cases:
assert case.raw_input_path.is_file(), (
f"Missing macro-spec fixture input for {case.variant}: {case.raw_input_path}"
)
assert (
case.raw_input_path.is_file()
), f"Missing macro-spec fixture input for {case.variant}: {case.raw_input_path}"


def test_macro_spec_fixture_parsers_load_sample_inputs(
Expand All @@ -44,9 +44,9 @@ def test_macro_spec_fixture_generators_create_cprs_ch_sheet(
for case in macro_spec_cases:
workbook = case.generator(case.raw_input_path)
try:
assert "CPRS - CH" in workbook.sheetnames, (
f"{case.variant}: generated workbook missing required CPRS - CH sheet"
)
assert (
"CPRS - CH" in workbook.sheetnames
), f"{case.variant}: generated workbook missing required CPRS - CH sheet"
finally:
workbook.close()

Expand All @@ -70,9 +70,9 @@ def test_macro_spec_range_level_outputs_match_expected_mosers_format(
actual_vols = [worksheet[f"D{row_number}"].value for row_number in range(10, 21)]
actual_allocations = [worksheet[f"E{row_number}"].value for row_number in range(10, 21)]

assert worksheet["B5"].value == parsed.ch_rows[0].counterparty, (
f"{macro_name}: CPRS - CH!B5 deviates from expected counterparty transformation"
)
assert (
worksheet["B5"].value == parsed.ch_rows[0].counterparty
), f"{macro_name}: CPRS - CH!B5 deviates from expected counterparty transformation"
assert actual_vols == expected_vols, (
f"{macro_name}: CPRS - CH!D10:D20 deviates from expected annualized-volatility "
"range transformation"
Expand Down
6 changes: 3 additions & 3 deletions tests/test_fixtures_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ def test_fixture_workbooks_and_presentations_open() -> None:
and path.name not in already_validated_fixture_names
)
assert fixture_paths, f"No .pptx/.xlsx fixtures found under {fixtures_root}."
assert len(fixture_paths) >= 10, (
"Expected representative fixture inventory under tests/fixtures."
)
assert (
len(fixture_paths) >= 10
), "Expected representative fixture inventory under tests/fixtures."

workbook_fixtures = [path for path in fixture_paths if path.suffix.lower() == ".xlsx"]
presentation_fixtures = [path for path in fixture_paths if path.suffix.lower() == ".pptx"]
Expand Down
18 changes: 9 additions & 9 deletions tests/test_futures_delta.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,9 @@ def test_locate_section_raises_when_missing_prior_month_col(self, tmp_path: Path
wb = load_mosers_workbook(_FIXTURE_PATH)
section = locate_futures_detail_section(wb)
ws = wb[section.sheet_name]
ws.cell(
row=section.header_col_row, column=section.prior_month_col
).value = "Current Month Notional"
ws.cell(row=section.header_col_row, column=section.prior_month_col).value = (
"Current Month Notional"
)
path = tmp_path / "missing_col.xlsx"
wb.save(path)

Expand All @@ -231,9 +231,9 @@ def test_write_prior_month_notional_populates_cells(self, tmp_path: Path) -> Non
desc = str(ws.cell(row=data_row, column=section.description_col).value or "").strip()
prior_val = ws.cell(row=data_row, column=section.prior_month_col).value
expected = _PRIOR_NOTIONALS.get(desc)
assert prior_val == pytest.approx(expected), (
f"Row {data_row} ({desc!r}): expected {expected}, got {prior_val}"
)
assert prior_val == pytest.approx(
expected
), f"Row {data_row} ({desc!r}): expected {expected}, got {prior_val}"

def test_write_prior_month_notional_values_are_numeric(self, tmp_path: Path) -> None:
"""Written prior-month values must be numeric (not strings)."""
Expand All @@ -244,9 +244,9 @@ def test_write_prior_month_notional_values_are_numeric(self, tmp_path: Path) ->
ws = wb[section.sheet_name]
for data_row in range(section.data_start_row, section.data_end_row + 1):
prior_val = ws.cell(row=data_row, column=section.prior_month_col).value
assert isinstance(prior_val, (int, float)), (
f"Row {data_row}: expected numeric, got {type(prior_val)}"
)
assert isinstance(
prior_val, (int, float)
), f"Row {data_row}: expected numeric, got {type(prior_val)}"

def test_write_only_modifies_prior_month_column(self, tmp_path: Path) -> None:
"""Only the prior-month notional column is modified; all other cells unchanged."""
Expand Down
1 change: 0 additions & 1 deletion tests/test_mosers_all_programs_output_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,3 @@ def test_all_programs_fixture_generates_using_documented_layout_contract() -> No
assert worksheet[first_alloc_cell].value == expected_allocation
finally:
workbook.close()

1 change: 0 additions & 1 deletion tests/test_mosers_ex_trend_output_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,3 @@ def test_ex_trend_fixture_generates_using_documented_layout_contract() -> None:
assert worksheet[first_alloc_cell].value == expected_allocation
finally:
workbook.close()

1 change: 0 additions & 1 deletion tests/test_mosers_trend_output_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,3 @@ def test_trend_fixture_generates_using_documented_layout_contract() -> None:
assert worksheet[first_alloc_cell].value == expected_allocation
finally:
workbook.close()

4 changes: 2 additions & 2 deletions tests/test_mosers_workbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ def test_resolve_cprs_ch_metric_row_bounds_tracks_template_row_shifts() -> None:
workbook = workbook_generation_module.load_mosers_template_workbook()
try:
worksheet = workbook["CPRS - CH"]
baseline_start, baseline_end = workbook_generation_module._resolve_cprs_ch_metric_row_bounds(
worksheet
baseline_start, baseline_end = (
workbook_generation_module._resolve_cprs_ch_metric_row_bounds(worksheet)
)
worksheet.insert_rows(baseline_start, amount=2)
shifted_start, shifted_end = workbook_generation_module._resolve_cprs_ch_metric_row_bounds(
Expand Down
Loading
Loading