Skip to content

chore: extract a shared JSON-write helper in the analytics static site export #4944

Description

@hunterckx

(Text courtesy of Claude)

Follow-up from #4942 / #4943, spun out of review rather than folded into that PR.

Problem

analytics/analytics_package/analytics/static_site/export.py writes its JSON output through ten near-identical blocks:

with (output_dir / "monthly_traffic.json").open("w") as f:
    json.dump(traffic_data.to_dict(orient="records"), f, indent=2)
print(f"  Wrote monthly_traffic.json ({len(traffic_data)} records)")

They appear at monthly_traffic.json, file_downloads.json, access_requests.json, file_download_events.json, search_queries.json, custom_events.json, event_{key}_detail.json, event_charts.json, config.json and meta.json — plus an eleventh copy as the tail of export_df_as_json. Each repeats the with / open("w") ceremony, indent=2, the two-space Wrote log prefix, and the filename twice (once as a path, once inside the message).

The concrete cost showed up in #4942: enabling ruff's PTH rules meant hand-applying the same os.path.joinpathlib change eleven times in this one file, and PTH118/PTH123 accounted for 27 of that PR's 33 violations. Beyond the churn, indent=2, the encoding, and the log convention can each drift independently across eleven sites, and the path/message filename pair can silently disagree.

Suggested fix

One module-level helper, then one call per output file:

def _write_json(path, payload, detail=None):
    with path.open("w") as f:
        json.dump(payload, f, indent=2)
    print(f"  Wrote {path.name}" + (f" ({detail})" if detail else ""))
_write_json(output_dir / "file_downloads.json", {"total": file_downloads}, f"total: {file_downloads}")
_write_json(output_dir / "config.json", config)

A detail=None parameter covers every existing message variant — N records, total: X, N queries, N events, N charts, and the bare Wrote config.json / Wrote meta.json — with byte-identical output. export_df_as_json's tail collapses into the same helper. Net effect is roughly −16 lines.

Why this wasn't done in #4943

#4942 scoped its PTH commit to the path-handling change with no unrelated cleanup, so that the commit stayed reviewable against the rule it was named for. The repetition is pre-existing — #4943 converted it, it did not create it.

Verification

  • npm run lint:python and npm run check-format:python pass clean, and the same steps pass in run-checks.yml CI.
  • Printed stdout and every generated JSON file must be byte-identical before and after, since this is a pure extraction. A fresh-venv generate_static_site.py run including historic_data_path (LungMAP), per the chore: retire legacy analytics formats — tracking #4913 convention, with the generated site output diffed against main — expect no differences beyond data/meta.json's generated_at timestamp.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions