Skip to content

fix: ExportMixin captures only outermost __init__ args for correct export/rebuild round-trips - #273

Draft
toby-coleman with Copilot wants to merge 4 commits into
mainfrom
copilot/fix-export-mixin-argument-issue
Draft

fix: ExportMixin captures only outermost __init__ args for correct export/rebuild round-trips#273
toby-coleman with Copilot wants to merge 4 commits into
mainfrom
copilot/fix-export-mixin-argument-issue

Conversation

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

ExportMixin wrapped __init__ at every level of the class hierarchy and merged all args into one dict, so subclasses that derive a parent's constructor argument would export both their own arg and the parent's computed arg — breaking reconstruction.

class DerivedFieldNames(DataWriter):
    def __init__(self, value_field: str, **kwargs):
        super().__init__(field_names=["time_stamp", value_field], **kwargs)

writer = DerivedFieldNames(name="writer", value_field="capacity_mwh")
writer.export()["args"]
# Before: {'name': 'writer', 'value_field': 'capacity_mwh', 'field_names': [...]}
# → DerivedFieldNames(**args) raises TypeError: got multiple values for 'field_names'

# After: {'name': 'writer', 'value_field': 'capacity_mwh'}
# → rebuilds correctly

Changes

  • plugboard/utils/export_mixin.py_save_args_wrapper now sets a re-entrancy flag on the instance before calling __init__. Nested super().__init__() wrappers detect the flag and skip saving. The flag is deleted in a finally block so no stale attributes persist on instances.

Copilot AI and others added 2 commits August 13, 2026 13:29
Co-authored-by: toby-coleman <13170610+toby-coleman@users.noreply.github.com>
Co-authored-by: toby-coleman <13170610+toby-coleman@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix export() argument capture in ExportMixin fix: ExportMixin captures only outermost __init__ args for correct export/rebuild round-trips Aug 13, 2026
Copilot AI requested a review from toby-coleman August 13, 2026 13:31
@toby-coleman

Copy link
Copy Markdown
Contributor

@copilot Can you add a minimal test for this

@github-actions

Copy link
Copy Markdown

Benchmark comparison for f452c7de (base) vs f38d1f23 (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.14-64bit/0001_base)     367.9127 (1.0)      380.3617 (1.01)     373.3145 (1.00)     5.0316 (1.76)     374.4442 (1.00)     7.5236 (2.66)          2;0  2.6787 (1.00)          5           1
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.14-64bit/0001_pr)         368.6108 (1.00)     376.6151 (1.0)      372.7368 (1.0)      2.8621 (1.0)      373.0445 (1.0)      2.8255 (1.0)           2;0  2.6829 (1.0)           5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

Co-authored-by: toby-coleman <13170610+toby-coleman@users.noreply.github.com>

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Can you add a minimal test for this

Added two unit tests in tests/unit/test_component.py (commit test: add unit tests for ExportMixin outermost-args fix):

  • test_export_captures_only_outermost_init_args — verifies that export()['args'] contains only the outermost constructor's arguments (not derived parent args), and that rebuilding from those args works.
  • test_export_no_stale_flag_on_instance — verifies the re-entrancy flag is cleaned up and leaves no stale attributes on instances.

@github-actions

Copy link
Copy Markdown

Benchmark comparison for f452c7de (base) vs ac72ad5f (PR)


------------------------------------------------------------------------------------------------------------------ benchmark: 2 tests -----------------------------------------------------------------------------------------------------------------
Name (time in ms)                                                                         Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_benchmark_process_run (pr/.benchmarks/Linux-CPython-3.14-64bit/0001_pr)         366.7561 (1.0)      379.0641 (1.0)      373.9058 (1.0)      4.6390 (1.0)      375.2914 (1.0)      5.7289 (1.0)           2;0  2.6745 (1.0)           5           1
test_benchmark_process_run (main/.benchmarks/Linux-CPython-3.14-64bit/0001_base)     382.7287 (1.04)     399.3943 (1.05)     388.1332 (1.04)     6.6391 (1.43)     385.4353 (1.03)     7.1702 (1.25)          1;0  2.5764 (0.96)          5           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

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.

bug: export() captures __init__ arguments from every class in the chain, so subclasses cannot be rebuilt from a dumped config

2 participants