Skip to content

Harden Rhiza sync schedule editing and tighten exception API typing#883

Draft
tschm with Copilot wants to merge 3 commits into
mainfrom
copilot/fix-sed-invocation-issue
Draft

Harden Rhiza sync schedule editing and tighten exception API typing#883
tschm with Copilot wants to merge 3 commits into
mainfrom
copilot/fix-sed-invocation-issue

Conversation

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

This PR applies the requested fixes across Rhiza make targets and exception typing. It removes fragile in-place sed backup behavior, corrects command chaining in summarise-sync, and refines exception signatures/payload handling in exceptions.py.

  • Rhiza sync workflow editing

    • Replaced sed -i.bak ... && rm ...bak with a temp-file rewrite + atomic move pattern in _apply-sync-schedule.
    • Avoids backup-file residue and removes BSD/GNU sed -i portability concerns.
  • Rhiza summarise target command flow

    • Updated summarise-sync to use $(MAKE) install-uv && ... instead of ;.
    • Ensures the summarise command only runs when install-uv succeeds.
  • Exception API/type adjustments

    • InvalidMaxBpsError.__init__ now uses Any for clearer intent than object.
    • MissingDateColumnError now consistently stores available as a list via defensive normalization/copying.
  • Focused exception coverage

    • Added targeted tests for MissingDateColumnError.available default/list-copy behavior.
# before
sed -i.bak "s|cron: '[^']*'|cron: '$(RHIZA_SYNC_SCHEDULE)'|" .github/workflows/rhiza_sync.yml && rm -f .github/workflows/rhiza_sync.yml.bak

# after
sed "s|cron: '[^']*'|cron: '$(RHIZA_SYNC_SCHEDULE)'|" .github/workflows/rhiza_sync.yml > .github/workflows/rhiza_sync.yml.tmp && \
mv .github/workflows/rhiza_sync.yml.tmp .github/workflows/rhiza_sync.yml
Original prompt
Please apply the following diffs and create a pull request.
Once the PR is ready, give it a title based on the messages of the fixes being applied.

[{"message":"The `sed -i.bak` invocation creates a backup file and then removes it. On macOS (BSD sed), `-i ''` is required for in-place editing without a backup, while GNU sed uses `-i` alone. Using `-i.bak` and then deleting the backup is a common cross-platform workaround, but if `sed` fails mid-run the `.bak` file may be left behind. A more robust approach would be to check whether the substitution actually changed the file (e.g. via `diff`) or to use a temp file pattern.","fixFiles":[{"filePath":".rhiza/rhiza.mk","diff":"diff --git a/.rhiza/rhiza.mk b/.rhiza/rhiza.mk\n--- a/.rhiza/rhiza.mk\n+++ b/.rhiza/rhiza.mk\n@@ -169,7 +169,8 @@\n \n _apply-sync-schedule: ## (internal) apply RHIZA_SYNC_SCHEDULE override to GitHub Actions sync workflow\n \t@if [ \"$(RHIZA_SYNC_SCHEDULE)\" != \"0 0 * * 1\" ] && [ -f .github/workflows/rhiza_sync.yml ]; then \\\n-\t\tsed -i.bak \"s|cron: '[^']*'|cron: '$(RHIZA_SYNC_SCHEDULE)'|\" .github/workflows/rhiza_sync.yml && rm -f .github/workflows/rhiza_sync.yml.bak; \\\n+\t\tsed \"s|cron: '[^']*'|cron: '$(RHIZA_SYNC_SCHEDULE)'|\" .github/workflows/rhiza_sync.yml > .github/workflows/rhiza_sync.yml.tmp && \\\n+\t\tmv .github/workflows/rhiza_sync.yml.tmp .github/workflows/rhiza_sync.yml; \\\n \t\tprintf \"${BLUE}[INFO] Applied custom sync schedule: $(RHIZA_SYNC_SCHEDULE)${RESET}\\n\"; \\\n \tfi\n \n"}]},{"message":"The `summarise-sync` target already lists `install-uv` as a prerequisite on line 181, so the explicit `$(MAKE) install-uv` call inside the `else` branch is redundant. More importantly, the semicolon-separated recipe means a failure of `install-uv` here won't abort the recipe (unlike `&&`). If the intent is to ensure `install-uv` succeeds before continuing, use `&&` instead of `;`, consistent with how the `sync` target chains commands on line 164.","fixFiles":[{"filePath":".rhiza/rhiza.mk","diff":"diff --git a/.rhiza/rhiza.mk b/.rhiza/rhiza.mk\n--- a/.rhiza/rhiza.mk\n+++ b/.rhiza/rhiza.mk\n@@ -182,7 +182,7 @@\n \t@if [ -n \"$(IS_MOTHER_REPO)\" ]; then \\\n \t\tprintf \"${BLUE}[INFO] Skipping summarise-sync in rhiza repository (no template.yml by design)${RESET}\\n\"; \\\n \telse \\\n-\t\t$(MAKE) install-uv; \\\n+\t\t$(MAKE) install-uv && \\\n \t\t${UVX_BIN} \"rhiza==$(RHIZA_VERSION)\" summarise .; \\\n \tfi\n \n"}]},{"message":"The `available` parameter accepts `list[str] | None` but internally converts it to a list or None in line 55. Consider accepting `list[str]` with an empty list as default to simplify the API and remove the need for None-checking in client code. Alternatively, document clearly when `available` should be None versus an empty list.","fixFiles":[{"filePath":"src/jquantstats/exceptions.py","diff":"diff --git a/src/jquantstats/exceptions.py b/src/jquantstats/exceptions.py\n--- a/src/jquantstats/exceptions.py\n+++ b/src/jquantstats/exceptions.py\n@@ -38,8 +38,9 @@\n         jquantstats.exceptions.MissingDateColumnError: ...\n     \"\"\"\n \n-    def __init__(self, frame_name: str, column: str | None = None, available: list[str] | None = None) -> None:\n+    def __init__(self, frame_name: str, column: str | None = None, available: list[str] = []) -> None:\n         \"\"\"Initialize with the frame name and, optionally, the missing column and available columns.\"\"\"\n+        available = [] if available is None else list(available)\n         if column is None:\n             msg = f\"DataFrame '{frame_name}' is missing the required 'date' column.\"\n         else:\n@@ -52,7 +52,7 @@\n         super().__init__(msg)\n         self.frame_name = frame_name\n         self.column = column\n-        self.available = list(available) if available is not None else None\n+        self.available = available\n \n \n class InvalidCashPositionTypeError(JQuantStatsError, TypeError):\n"}]},{"message":"The parameter type `object` is too broad for `max_bps`. Consider using a more specific type hint like `int | float | object` or `typing.Any` to better communicate the expected input types while still allowing arbitrary values for the error message formatting.","fixFiles":[{"filePath":"src/jquantstats/exceptions.py","diff":"diff --git a/src/jquantstats/exceptions.py b/src/jquantstats/exceptions.py\n--- a/src/jquantstats/exceptions.py\n+++ b/src/jquantstats/exceptions.py\n@@ -15,7 +15,9 @@\n \n from __future__ import annotations\n \n+from typing import Any\n \n+\n class JQuantStatsError(Exception):\n     \"\"\"Base class for all JQuantStats domain errors.\"\"\"\n \n@@ -243,7 +244,7 @@\n         jquantstats.exceptions.InvalidMaxBpsError: max_bps must be a positive integer, got 0.\n     \"\"\"\n \n-    def __init__(self, max_bps: object) -> None:\n+    def __init__(self, max_bps: Any) -> None:\n         \"\"\"Initialize with the offending value.\"\"\"\n         super().__init__(f\"max_bps must be a positive integer, go...

Copilot AI changed the title [WIP] Fix sed invocation for cross-platform compatibility Harden Rhiza sync schedule editing and tighten exception API typing Jul 12, 2026
Copilot finished work on behalf of tschm July 12, 2026 10:17
Copilot AI requested a review from tschm July 12, 2026 10:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants