From 3dcdb34b58767206f5b850e19b35e7d8c3be23d1 Mon Sep 17 00:00:00 2001 From: phobicdotno Date: Wed, 29 Apr 2026 10:17:07 +0200 Subject: [PATCH] fix(symbol-config): mutate configured_access via get_all_signatures, not configured view (#7) set_symbol_access and set_signature_access_bulk both looked up the target signature via sc_obj.get_only_configured_signatures() first and only fell back to get_all_signatures() if not found. The objects returned by get_only_configured_signatures() are a read-only view; assigning to .configured_access on them raises: The access of the variable can only be changed in the list of all signatures/data types. This was hidden during initial testing because the bulk variant was exercised before any variables were configured (so the configured view was empty and the all-signatures fallback fired). Once the configured set was populated, the single-var set_symbol_access path always picked up the read-only object and broke. Fix: always look up the mutation target via get_all_signatures(); use get_only_configured_signatures() only as a tracking-only flag for 'was this signature already exported'. Verified live on MCPTest.project under SP22 P1: bulk-set PLC_PRG to ReadWrite (4 vars), then per-var set_symbol_access PLC_PRG.s1 = None succeeds and list_configured_symbols reflects effective_access=None on s1. Co-authored-by: Karstein Phobic Nyvold Kvistad --- src/scripts/set_signature_access_bulk.py | 18 +++++++------ src/scripts/set_symbol_access.py | 34 ++++++++++++++---------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/scripts/set_signature_access_bulk.py b/src/scripts/set_signature_access_bulk.py index a501f79..04c057e 100644 --- a/src/scripts/set_signature_access_bulk.py +++ b/src/scripts/set_signature_access_bulk.py @@ -80,18 +80,20 @@ try: library_id = LIBRARY_ID if LIBRARY_ID else None + # IMPORTANT: configured_access is mutable ONLY on signature objects + # obtained from get_all_signatures(); the objects returned by + # get_only_configured_signatures() are a read-only view and assigning + # to .configured_access on them raises + # "The access of the variable can only be changed in the list + # of all signatures/data types." + # So we always look up via get_all_signatures, never the configured + # view, for the mutation target. sig = None try: - configured = sc_obj.get_only_configured_signatures() - sig = _find_signature_in(configured, SIGNATURE_FQN, library_id) + all_sigs = sc_obj.get_all_signatures(False) + sig = _find_signature_in(all_sigs, SIGNATURE_FQN, library_id) except Exception: pass - if sig is None: - try: - all_sigs = sc_obj.get_all_signatures(False) - sig = _find_signature_in(all_sigs, SIGNATURE_FQN, library_id) - except Exception: - pass if sig is None: try: all_sigs = sc_obj.get_all_signatures(True) diff --git a/src/scripts/set_symbol_access.py b/src/scripts/set_symbol_access.py index a80c8be..f54eba8 100644 --- a/src/scripts/set_symbol_access.py +++ b/src/scripts/set_symbol_access.py @@ -122,30 +122,36 @@ try: requested_access = _resolve_access(ACCESS) print("DEBUG: requested_access resolved to %r" % requested_access) - # Try the configured set first (these are the variables already - # selected for export). Fall back to the all-signatures view if the - # variable isn't yet configured -- setting access on a not-yet-configured - # variable is the standard way to "tick" it. + # IMPORTANT: configured_access is mutable ONLY on signature objects + # obtained from get_all_signatures(); the objects returned by + # get_only_configured_signatures() are a read-only view and assigning + # to .configured_access on them raises + # "The access of the variable can only be changed in the list + # of all signatures/data types." + # So we always look up via get_all_signatures first. The configured + # view is kept only as a final fallback (and to report whether the + # variable was already exported), never as the mutation target. sig = None library_id = LIBRARY_ID if LIBRARY_ID else None try: - configured = sc_obj.get_only_configured_signatures() - sig = _find_signature_in(configured, SIGNATURE_FQN, library_id) + all_sigs = sc_obj.get_all_signatures(False) + sig = _find_signature_in(all_sigs, SIGNATURE_FQN, library_id) except Exception as e: - print("DEBUG: get_only_configured_signatures failed: %s" % e) - found_in_configured = sig is not None - if sig is None: - try: - all_sigs = sc_obj.get_all_signatures(False) - sig = _find_signature_in(all_sigs, SIGNATURE_FQN, library_id) - except Exception as e: - print("DEBUG: get_all_signatures(False) failed: %s" % e) + print("DEBUG: get_all_signatures(False) failed: %s" % e) if sig is None: try: all_sigs = sc_obj.get_all_signatures(True) sig = _find_signature_in(all_sigs, SIGNATURE_FQN, library_id) except Exception as e: print("DEBUG: get_all_signatures(True) failed: %s" % e) + # Tracking-only: was this signature already in the configured set? + found_in_configured = False + try: + configured = sc_obj.get_only_configured_signatures() + if _find_signature_in(configured, SIGNATURE_FQN, library_id) is not None: + found_in_configured = True + except Exception: + pass if sig is None: raise RuntimeError( "Signature '%s' not found (library_id=%s). "