Skip to content

Merge extraction and feature-branch#66

Merged
ssweber merged 25 commits intomainfrom
extract-click-plc-core
Feb 27, 2026
Merged

Merge extraction and feature-branch#66
ssweber merged 25 commits intomainfrom
extract-click-plc-core

Conversation

@ssweber
Copy link
Owner

@ssweber ssweber commented Feb 27, 2026

No description provided.

ssweber and others added 25 commits February 1, 2026 14:29
  Phase 0 Summary

  Phase 0a: Enforce Unique Block Names

  - Added get_all_block_names() and is_block_name_available() functions to check for duplicate block names
  - Updated AddBlockDialog to accept a validation callback and reject duplicate names with an error message
  - Added is_duplicate_block_name() method to AddressStore
  - Extended validate_comment() to check for duplicate block names during row validation
  - Rows with duplicate block names are now marked as invalid with a comment_error

  Phase 0b: Add Auto-Suffix for T/TD, CT/CTD

  - Added _transform_block_name_for_pair() function to handle _D suffix transformation
  - Added apply_block_tag_for_interleaved_pair() method to BlockService
  - Updated _sync_interleaved_pair() in AddressStore to use the new suffix-aware sync
  - T/CT blocks now use base names (e.g., "Pumps"), TD/CTD blocks get "_D" suffix (e.g., "Pumps_D")

  Phase 0c: Move Multi-Row Functions to blocktag.py

  - Moved find_paired_tag_index, find_block_range_indices, compute_all_block_ranges, validate_block_span,
  get_all_block_names, and is_block_name_available from block_service.py to blocktag.py
  - block_service.py now imports and re-exports these functions for backwards compatibility
  - BlockService class remains in block_service.py for editor coordination operations

  1. Closing tags no longer marked as duplicates - The logic now recognizes that </BlockName> is supposed to match
  <BlockName>. Only opening and self-closing tags define a "block" that can be a duplicate.
  2. Validation now works at load time - Changed from using get_unified_view() (which is None during initial load) to
  using visible_state directly, so all existing blocks are validated when data is first loaded.
…t coverage

**Details:**
*   **Float Formatting:** Updated `storage_to_display` for `FLOAT` types to use the `.7G` format specifier. This correctly handles scientific notation for extreme values (e.g., `3.402823E+38`) and automatically trims trailing zeros, replacing the previous conditional `.6g` logic.
*   **Test Coverage:**
    *   Added `test_snapshot_data_consistency` to validate specific project data points (DF1-DF3, DH1-DH3, YD1-YD2), ensuring correct scientific notation and hex padding.
    *   Added edge cases for `INT` and `INT2` specifically regarding negative number handling and bit-masking.
    *   Added round-trip tests for `FLOAT` (IEEE-754 conversion) and `HEX` (ensuring 4-digit uppercase padding `0000`-`FFFF`).
    *   Added support checks for `TXT` type space characters.
Delete models/constants.py and move all constants, address helpers,
and validation to pyclickplc. Slim address_row.py to just the
AddressRow dataclass. Replace ADDRESS_RANGES with BANKS across
15 source files and 5 test files. Add pre-switch tests for
AddressRow derived properties.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract PLC memory bank configuration, address parsing, and validation
logic from ClickNick into standalone pyclickplc modules. Introduces
BankConfig frozen dataclass, parse_address strict parser, and simplified
AddressRecord model. 93 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…range

Skeleton creation and view builder now iterate only the 160 valid sparse
addresses for X/Y instead of all 816 in the contiguous range.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
storage_to_display is now datatype_to_display(storage_to_datatype(new_value, type_code))
parse_address_display is now parse_address
Replace from pyclickplc import ... with explicit submodule imports (addresses, banks, validation, dataview) across src/tests.
Remove dependency on pyclickplc.dataview.TypeCode; define local TypeCode constants in dataview_row.py from MEMORY_TYPE_TO_CODE.
Delete duplicated CDV verification internals in verification.py and delegate to pyclickplc.dataview.check_cdv_files.
Keep existing clicknick verification API shape (verify_cdv_files, run_verification) intact while switching implementation.
Full clicknick test suite passes after migration.
Restored local export_cdv, get_dataview_folder, list_cdv_files in clicknick.views.dataview_editor.cdv_file.
Added canonical read_mdb_csv in clicknick.data.data_source returning dict[int, AddressRow].
Kept load_addresses_from_mdb_dump as compatibility alias to read_mdb_csv.
Updated imports/call sites, added tests for folder discovery and MDB CSV parsing, and added changelog entry.
add check_cdv_files() to cdv_file.py
update verification.py to import local check_cdv_files
add check_cdv_files coverage in test_cdv_file.py
… tests

- Switch DataView panel CDV calls to local cdv_file wrappers (no direct load_cdv/save_cdv imports from pyclickplc)
- Update new_value handling for native semantics (unset=None, has_new_values via is not None)
- Add compatibility wrappers in dataview_editor/cdv_file.py on top of read_cdv/write_cdv
- Remove duplicated extracted dataview model tests
- Trim test_cdv_file.py to ClickNick-specific folder/helper coverage only
- Keep ClickNick behavior stable while pyclickplc API is simplified
…ry, toolbar layout

- Fix Tcl interpreter deadlock on window close: replace blocking
  disconnect(block=True) with fire-and-forget on daemon thread to avoid
  deadlock where service callbacks need Tcl lock held by blocked UI thread
- Remove unsafe block parameter from _disconnect_modbus entirely
- Add dataview_folder parameter to SharedDataviewData so CSV-only mode
  can discover CDV files in the same directory as the loaded CSV
- Move Modbus toolbar to its own row below Nickname/Insert toolbar
- Add View > Modbus Toolbar toggle to show/hide connection controls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clear stale Click connection metadata when a window closes or no instances are found,
and prevent CSV loads from re-entering dead-window monitoring.

- add `_clear_connection_state()` to centralize connected window reset
- clear connection/title state when instance refresh finds no windows
- in `load_csv()`, only start monitoring if the connected Click window still exists
- if connection is stale, keep CSV loaded and reset stale instance selection
- in `_handle_window_closed()`, only force-disconnect data for MDB-backed sources
  (do not tear down CSV-backed data)

Add regression tests for:
- loading CSV with stale connection does not restart monitoring and clears connection
- window-close handling preserves CSV-backed store/data source
- Add ⚡ Modbus checkbutton to nickname toolbar (hidden by default)
  that shows/hides the Modbus toolbar row and New Value/Write/Live columns
- Flash Live cells green briefly when values change
- Replace inline error/state labels with popups and button text
  (Connect → Connecting… → Disconnect → Disconnecting…)
- Transition to disconnected state on write transport errors
- Window resizes when toggling Modbus columns on/off

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…clickplc

Replace local SYSTEM_NICKNAME_TYPES constant and post-hoc underscore
error filtering with pyclickplc's is_system flag. Remove dead
system_nickname_issues infrastructure from VerificationResult and app UI.
System types (SC/SD/X) also skip the NON_EDITABLE initial value check
since the PLC can preset those values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- add `block_logic` view-model layer for Block panel tree construction
- group UDT-style block names (`Base.field`) under `Base` parents
- keep non-UDT names (`plain`, `named_array`, `block`) as flat top-level items
- preserve existing block selection callback contract (`on_block_select(leaves)`)
- make UDT parent nodes actionable with aggregated child addresses
- dedupe aggregated parent addresses by first occurrence of `(memory_type, address)`
- support duplicate same-field child blocks as separate actionable rows
- preserve unsorted first-occurrence ordering for top-level and child items
- support `A→Z` sorting for both top-level nodes and UDT child fields
- refactor `BlockPanel` rendering to recursive tree insertion
- preserve expanded/collapsed UDT parent state across refresh/sort toggles
- keep color tagging for actionable block rows; leave UDT parent rows uncolored
- add Dataview guard so paired T/TD and CT/CTD prompt appears only for pure `T` or pure `CT` selections
- add tests for block tree behavior and Dataview pairing guard:
  - `tests/test_block_logic.py`
  - `tests/test_dataview_block_select.py`
pyclickplc now treats SC, SD, and X as system nickname types, allowing system-generated names (for example `_IO1_Module_Error` and SC/SD names with reserved punctuation) when `is_system=True`.

This updates ClickNick’s AddressStore row validation to apply system nickname rules for all `SYSTEM_NICKNAME_TYPES` instead of validating edited rows as non-system nicknames. This prevents valid system nicknames from being incorrectly reported as nickname errors.

Also adds regression tests covering both loaded and edited system nicknames for:
- SC: `Comm/Port_1`
- SD: `_Fixed_Scan_Time(ms)`
- X: `_IO1_Module_Error`

Result: system nicknames are no longer falsely flagged while duplicate checks and other validation rules remain intact.
…tem exceptions to loaded values

Updates ClickNick to match the hardened pyclickplc nickname API and tighten UI validation behavior.

## What changed

- Removed `is_system` usage in ClickNick validation wrappers/callers.
- Switched all nickname validation paths to pass explicit `system_bank` when needed.
- Kept system-name exceptions narrow in `AddressStore`:
  - SC/SD: allowed only when nickname is unchanged from loaded base value
  - X: allowed only when nickname is unchanged from loaded base value and matches `_IO...`
- User-entered system-style nicknames are now validated with normal rules.
- Updated loaded-error masking behavior so nickname edits no longer keep stale `loaded_with_error` masking.

## Why

This prevents overly permissive behavior for user edits while still allowing PLC-generated system nicknames that already exist in loaded data.

## Tests

Added/updated regression coverage for:
- loaded SC/SD/X system nicknames
- user-entered SC/SD system-style nicknames (invalid)
- user-entered X `_IO...` nicknames (invalid)
- edited loaded system nicknames (invalid)
- clearing loaded validation masking after nickname edits
@ssweber ssweber merged commit ef099ac into main Feb 27, 2026
3 checks passed
@ssweber ssweber deleted the extract-click-plc-core branch February 27, 2026 14:32
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.

1 participant