Module Development¶
How to add, modify, and test pycWB modules following project conventions.
Module Structure¶
Every module follows this layout:
pycwb/modules/<module_name>/
├── __init__.py
├── <module_name>.py # Main implementation
├── <sub_feature>.py # Optional sub-modules
├── utils.py # Optional helpers
└── tests/
├── __init__.py
└── test_<feature>.py # Unit tests
Adding a New Module¶
Create the directory under
pycwb/modules/:mkdir -p pycwb/modules/my_module/tests touch pycwb/modules/my_module/__init__.py touch pycwb/modules/my_module/tests/__init__.pyWrite the module — a single entry function that takes a
Configand returns results:# pycwb/modules/my_module/my_module.py import logging logger = logging.getLogger(__name__) def process(config): """One-line summary of what this module does.""" # Read config params param = config.some_param # Do work result = ... return resultWire into the pipeline — add the call to
pycwb/workflow/subflow/process_job_segment.pyin the correct stage.Add tests — see below.
Register config parameters — if your module needs new YAML parameters, add them to
pycwb/constants/user_parameters_schema.pywith defaults, types, and descriptions.
Module Communication¶
Modules must not import sideways from each other. Communication flows through:
Config: parameters flow downward from
Config.Return values: each module returns plain Python objects or NumPy arrays.
Types: shared data classes live in
pycwb/types/(e.g.,WaveSegment,Cluster,PixelArrays).
This keeps modules independently testable and avoidable of circular imports.
Choosing Numba vs JAX¶
Criterion |
Use Numba |
Use JAX |
|---|---|---|
Data pattern |
Loops over time-delay batches |
Batched vector/matrix operations |
Compilation |
|
|
Parallelism |
|
Device-agnostic (CPU or GPU) |
Example |
|
|
Memory |
Standard Python/NumPy |
Must explicitly free JAX device buffers after each lag |
Rule of thumb: prefer Numba for CPU-bound inner loops on small arrays; prefer JAX for large batched operations that will benefit from GPU acceleration in the future. Write JAX code in a device-agnostic way. Never use pure NumPy for hot paths.
Writing Tests¶
# pycwb/modules/my_module/tests/test_my_module.py
import unittest
from pycwb.modules.my_module import process
class TestMyModule(unittest.TestCase):
def setUp(self):
# Create minimal config for testing
from pycwb.config import Config
self.config = Config()
self.config.some_param = 42
def test_process_basic_returns_expected(self):
result = process(self.config)
self.assertIsNotNone(result)
def test_process_edge_case_empty_input(self):
self.config.some_param = 0
result = process(self.config)
self.assertEqual(result, [])
Config Schema Conventions¶
When adding parameters to user_parameters_schema.py:
"my_new_param": {
"type": "number",
"default": 3.0,
"minimum": 0.0,
"maximum": 10.0,
"description": "My new parameter controlling widget size [arbitrary units]"
}
Use descriptive names matching the module (
my_module_paramnotx).Provide sensible defaults — users shouldn’t need to set every parameter.
Document units in the description.
Auto-derived fields (
rateANA,nRES,WDM_level,max_delay) must not be set manually by users — they are computed from other parameters.
Deprecation Policy¶
ROOT and C++ bindings are being phased out. Do not write new code that depends on them.
Existing ROOT-dependent paths are guarded by
pycwb.utils.check_ROOT.has_ROOT().New wavelet/WDM code must use the pure-Python
wdm-waveletpackage.