v1.9.8 - Sampler Utility and Iterator Extraction (2025-12-29)#
What Changed?#
This release continues Phase 2 decomposition by extracting utility functions and iterators from the Sampler class into dedicated modules.
The _helpers.py module provides type conversion and progress display utilities, while _iterators.py contains count-based and time-based iteration logic.
All functionality is preserved through the existing modular package structure with zero breaking changes.
What’s New#
Utility Functions Module (_helpers.py)#
What it does: Extracts three static utility functions from the Sampler class into a dedicated helpers module. These functions handle type conversion, progress display, and test data generation.
Functions extracted:
sanitize(event: list) -> list: Converts raw CSV string values to proper Python typesEmpty strings →
NoneNumbers →
int(if whole) orfloat(if decimal)Non-numbers → remain as strings
tqdm_wrapper(iterable, desc=None, show=True): Conditionally wraps iterables with progress barsshow=True: Displays tqdm progress barshow=False: Returns iterable unchangedUseful for interactive vs batch processing
mock_sample(*args, **kwargs): Generates hardcoded test data["mock_event"]Used for unit testing without hardware
Accepts any arguments (ignored)
Code examples:
# Type conversion
from haniwers.v1.daq.sampler._helpers import sanitize
raw_csv_row = ["100", "200.5", "", "invalid"]
cleaned = sanitize(raw_csv_row)
# Returns: [100, 200.5, None, "invalid"]
# Progress bar display
from haniwers.v1.daq.sampler._helpers import tqdm_wrapper
# Show progress
for item in tqdm_wrapper(range(1000), desc="Processing", show=True):
process(item)
# No progress (batch mode)
for item in tqdm_wrapper(range(1000), desc="Processing", show=False):
process(item)
Iterator Functions Module (_iterators.py)#
What it does: Extracts iteration logic into generator functions for count-based and time-based acquisition loops. These generators encapsulate the control flow for both sampling modes.
Functions extracted:
count_based_iterator(count: int): Generator that yieldscounttimesUsed for
acquire_by_count()modeYields exactly N times before stopping
time_based_iterator(duration: float, sleep_interval: float): Generator for fixed-duration loopsUsed for
acquire_by_time()modeYields until duration elapsed
Respects sleep_interval between yields
Code examples:
from haniwers.v1.daq.sampler._iterators import count_based_iterator
# Collect exactly 1000 events
for _ in count_based_iterator(1000):
event = device.read_event()
csv_writer.write_row(event)
# Time-based acquisition (30 seconds, 0.1s sleep)
for _ in time_based_iterator(30.0, 0.1):
event = device.read_event()
csv_writer.write_row(event)
Installation#
Quick Start#
# Get the release
git checkout v1.9.8
# Setup
task env:setup
# Run CLI
haniwers-v1 --help
What’s Different from the Last Version?#
✅ Added#
New
src/haniwers/v1/daq/sampler/_helpers.pymodule with utility functions (sanitize, tqdm_wrapper, mock_sample)New
src/haniwers/v1/daq/sampler/_iterators.pymodule with generator functions (count_based_iterator,time_based_iterator)Comprehensive docstrings with usage examples for all new modules
🔧 Changed#
Reorganized
src/haniwers/v1/daq/sampler/_base.pyto import helpers and iterators from new modulesNo changes to public API or CLI functionality
🐛 Fixed#
No bug fixes in this release
Is It Safe to Upgrade?#
Backward Compatible: ✅ Yes
All existing imports and APIs continue to work without modification. The extraction of utility functions and iterators into dedicated modules is a pure refactoring with no breaking changes.
Tests Passed#
✅ Builds without errors
✅ All 133 unit tests passing (DAQ module)
✅ Sampler functionality tests passing (10 tests covering count/time/run modes)
✅ MAC address tests passing (3 essential tests)
✅ Helper function tests verified
✅ Iterator function tests verified
✅ Pre-commit hooks passing (ruff format, YAML, etc.)
Release Details#
Date: 2025-12-29
Version: v1.9.8
Files Changed: 3 (created
_helpers.py,_iterators.py; updated_base.pyimports)Commits:
6292a99: refactor(daq/sampler): extract static helper functions to _helpers.py
b0ce175: refactor(daq/sampler): extract iterator functions to _iterators.py
81b0d45: bump: version 1.9.7 → 1.9.8
Next Steps#
Phase 2.2 (v1.9.9 planned): Reader and Writer Module Decomposition#
src/haniwers/v1/daq/sampler/
├── __init__.py # Re-exports all classes
├── _base.py # Sampler base class (initialization, coordination)
├── _reader.py # EventReader (read_event, stream_events, collect_events)
├── _writer.py # EventWriter (save_events, acquire_by_count, acquire_by_time)
├── _iterators.py # Iterators (count_based_iterator, time_based_iterator) ✓
└── _helpers.py # Static helpers (sanitize, tqdm_wrapper, mock_sample) ✓
Benefits of Phase 2.2:
Single Responsibility Principle (SRP) fully applied
Each module ~300-400 lines instead of 1,591 lines
Improved testability and code organization
Clearer relationships between reader, writer, and orchestration layers
Phase 3 (v1.10.0 planned): Technical Debt Resolution#
Complete removal of deprecated
DaqConfigandScanConfigmodelsRemoval of TODO comments with implementations
Integration test stabilization
Performance optimization if needed
v1 → v2 Transition#
This refactoring prepares v1 for stable maintenance mode while providing:
Clean codebase for v2 migration
Reusable helper modules for v2
Clear architectural patterns to follow
Architecture Decision#
This modularization follows the Single Responsibility Principle (SRP):
Each module has one reason to change
Dependencies flow downward (high-level → utilities)
Public API remains unchanged
This pattern will be applied to other large modules in future releases:
config/model.py(1,184 lines) → Phase 2.2cli/options.py(770 lines) → Phase 2.3
See project constitution for more details on architectural principles.