Skip to content

Sanitiser update and fix - #90

Merged
dylanjmcconnell merged 10 commits into
mainfrom
comment-fix
Sep 14, 2026
Merged

dylanjmcconnell merged 10 commits into
mainfrom
comment-fix

Conversation

@dylanjmcconnell

@dylanjmcconnell dylanjmcconnell commented Aug 29, 2026 •

Copy link
Copy Markdown
Member

Some of the cells in v7.8 of the workbook have a new type of within-cell footnotes. In addition, previous sanitisation of in-cell comments also silently mis-handles some comments (this effects v7.8 but also some older versions too). This PR address both of these by updating and fixing sanitisers.py

New footnote style

There are now square-bracketed footnotes, immediately next to a value (e.g. 750[footnote14]). This pattern not captured by any of the existing sanitisers - so a new one is added as follows:

def _remove_series_bracketed_footnotes(str):
    return series.str.replace(r"\[footnote\s*\d+\]", "", regex=True)

(and the function added to the list of santisers to run)

Mis-handled santisation

_remove_series_notes_after_values is intended to handle the common 123 (some note) shape. But the existing regex patterns stops at a $ sign (and also : and probably others) - so some things are silently not-sanitised. For example:

1,749.5 (ElectraNet has advised that approximately $23 million of this amount relates to approved early works costs ...)

Is returned as:

1749.5$23 million of this amount relates to approved early works costs…

(i.e. the bit from the parenthesis to the $ is removed, but not anything after the $ sign)

Have up updated the santiser to capture broader more generic pattern, from:

r"^([0-9\.]+)\s+(?:(\([\w\s\.\<\=\-\/\,]+\)?\s?)+)"

to:

r"^([0-9\.]+)\s+\(.*$"

This is a much more generic regex - i.e. basically capture anything following whitespace and opening parenthesis - i.e. anything after <number><whitespace>(. Not just the whitelist of characters in the original (not sure if there was a reason for that original white list?).

I did regenerate the example outputs to see if there were negative side effects of this .. I did spot two patterns that are not footnotes, and captured by this (but also - previously there were incorrectly captured as footnotes, and maybe are a different category of problem / issue):

  1. gas_system_properties_pipelines: 350 (Summer) / 362 (Winter) - now sanitises as 350 with new regex (and previously as 350362 (Winter))
  2. rez_augmentation_options_VIC table: 4600 (V8: 3,000) - now sanitises as 4000 with new regex (and previously as 4600: 3000))

So this PR would make these values go from "incorrectly treated as comments and poorly sanitised", to "incorrectly treated as comments and slightly better sanitised". The reason I say "slightly better" is mainly because it means the the rest of the table has the consistent dyptes (rather the float and str in same col). Perhaps this is better dealt with as a separate issue, if at all (... pretty niche issue at the end of the day, I think). But open to other suggestions.

I did make a table with current output, vs updated output and original text (.. mainly because was hard to spot changes in the git diffs). I've put it here incase it's handy for anyone else to look at too: Comment changes and fixes for workbook 7.8.

Tests:

Added some basic tests for the new / updated functions intests/test_sanitisers.py:

  • test_remove_series_notes_after_values_with_special_characters
  • test_remove_series_bracketed_footnotes.

File changes:

  • src/isp_workbook_parser/sanitisers.py
  • tests/test_sanitisers.py

And then a handful of output csvs in the example_output csv folder

- simplyfy regex (ignored everything after a whitespace and parenthesis)
- updated doc string (make it clear that everything after parenthesis dropped)
…w footnote type

- relative simple regex for footnotes like 750[footnote14]
@codecov

codecov Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
src/isp_workbook_parser/sanitisers.py 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

_remove_series_notes_after_values reduced a cell to the value before its
first parenthesis. For cells holding two values, each with its own note,
that silently discarded every value but the first and then cast the
result to a numeric type, so consumers saw a plausible-looking number
with no signal that half the cell was gone. For example
'930 (NSW works) 964 (QLD works)' became 930, and 'Storage properties'
lost the 325 MW pump capacity from '250 (generation) 325 (pump)'.

Add _where_multiple_values_with_notes to detect these cells and guard the
substitution with it, leaving them as text. The column then fails to cast
to a numeric type, which is how such cells behaved before the truncation
was widened.

A second value is only recognised where nothing but non-alphanumeric
characters separates it from the first note's closing parenthesis, which
distinguishes it from a footnote reference such as
'400 (with VNI SIPS) - Note 8'. Across all five packaged workbooks this
preserves 13 cells and still truncates the other 187.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QBSw6PJqTrzzZHU6xg7cb
nick-gorman and others added 4 commits August 31, 2026 11:54
Matches the style of the other sanitisers, which pass their patterns
directly to the pandas string method. The pattern is unchanged, so
example_output is unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QBSw6PJqTrzzZHU6xg7cb
The three rows were grouped under one comment implying none of them
needed the predicate to fire. That is true of the two whose shape
substitution 1 never matches, but 930 - NSW works 964 - QLD works is
still cut down to 930 by substitution 2, dropping a value. Split it out
and label it as the known gap it is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QBSw6PJqTrzzZHU6xg7cb
Maybe overkill - but just changed placement of the where filter to after *all* the cleaning regex (not just first)
Keep cells holding two values as text instead of truncating to the first

@nick-gorman nick-gorman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the changes to the output this seems to be strictly an improvement on current data. I've just got a few questions/comments which might make it more robust on future datasets. Up to you if you think they are worth implementing.

)
series = series.str.replace(
keep_full_text = _where_multiple_values_with_notes(series)
cleaned = series.str.replace(r"^([0-9\.]+)\s+\(.*$", r"\1", regex=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a thought, should the subsequent regex replacements have the same fix applied to them as well, so they don't also stop at a $?

Comment thread src/isp_workbook_parser/sanitisers.py Outdated
@@ -68,6 +68,7 @@ def _values_casting_and_sanitisation(df: pd.DataFrame) -> pd.DataFrame:
_remove_series_trailing_asterisks,
_remove_series_thousands_commas,
_remove_series_notes_after_values,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be a bit more robust if we move the _remove_series_bracketed_footnotes up the pipeline to before _remove_series_notes_after_values, that way a bracketed footnote, say after the first number can't intefer with _remove_series_notes_after_values from firing?? Also moving _remove_series_trailing_footnotes to before _remove_series_notes_after_values could also guard a trailing footnote from being caught as second value.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also maybe we don't want the bracketed footnote firing on column headers, but if we didn't mind that we could move its regex to custom_string_replacements.py

@dylanjmcconnell

Copy link
Copy Markdown
Member Author

Thanks Nick!

fyi change the pipeline ordering as you suggest (.. in part because it was straightforward).
'
I didn't apply the same regex fix to the other patterns (.. i.e. so they also don't stop at a $ etc). Maybe overly conservative - (e.g. might accidentally let something through)..

But also not entirely theoretical - just noticed that the update would impact some of the carbon budget ranges ("28-33% reduction" would end up as 28, and a float rather than string) .. though that is kind of another of a problem - a range in a cell 🫠 .

Anyway I think best leave that for now.

@dylanjmcconnell
dylanjmcconnell merged commit 16a8149 into main Sep 14, 2026
18 checks passed
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