Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,5 @@
+ r".*",
# attempted fix of '406 Client Error: Not Acceptable for url'
# https://github.com/sphinx-doc/sphinx/issues/1331
join(project_meta["project"]["urls"]["repository"], "commit", r"[0-9a-fA-F]+")
join(project_meta["project"]["urls"]["repository"], "commit", r"[0-9a-fA-F]+"),
]
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
attrs
dask
entrypoints
matplotlib
numpy
Expand All @@ -8,6 +7,6 @@ h5py
pint
pytest
stamina
tiled
tox
scipy
uncertainties
7 changes: 4 additions & 3 deletions src/modacor/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
# __init__.py

__version__ = '0.0.0'
__version__ = "0.0.0"

from pint import UnitRegistry, set_application_registry
ureg = UnitRegistry(system='SI')

ureg = UnitRegistry(system="SI")
Q_ = ureg.Quantity
# recommended for pickling and unpickling:
# recommended for pickling and unpickling:
set_application_registry(ureg)
ureg.formatter.default_format = "~P"
ureg.setup_matplotlib(True)
20 changes: 11 additions & 9 deletions src/modacor/dataclasses/messagehandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# # -*- coding: utf-8 -*-

import logging

logger = logging.getLogger(__name__)


Expand All @@ -13,7 +14,8 @@ class MessageHandler:
Args:
level (int): The logging level to use. Defaults to logging.INFO.
"""
def __init__(self, level: int = logging.INFO, name: str = 'MoDaCor', **kwargs):

def __init__(self, level: int = logging.INFO, name: str = "MoDaCor", **kwargs):
self.level = level
self.name = name

Expand All @@ -23,7 +25,7 @@ def __init__(self, level: int = logging.INFO, name: str = 'MoDaCor', **kwargs):
self.consoleLogHandler = logging.StreamHandler()
self.consoleLogHandler.setLevel(level)

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
self.consoleLogHandler.setFormatter(formatter)
self.logger.addHandler(self.consoleLogHandler)

Expand All @@ -33,20 +35,20 @@ def log(self, message: str, level: int = None, name: str = None):

if name is None:
name = self.name

self.logger(message, level=level, name=name)

def info(self, message: str):
self.log(message, level=logging.INFO, name='MoDaCor')
self.log(message, level=logging.INFO, name="MoDaCor")

def warning(self, message: str):
self.log(message, level=logging.WARNING, name='MoDaCor')
self.log(message, level=logging.WARNING, name="MoDaCor")

def error(self, message: str):
self.log(message, level=logging.ERROR, name='MoDaCor')
self.log(message, level=logging.ERROR, name="MoDaCor")

def critical(self, message: str):
self.log(message, level=logging.CRITICAL, name='MoDaCor')
self.log(message, level=logging.CRITICAL, name="MoDaCor")

def debug(self, message: str):
self.log(message, level=logging.DEBUG, name='MoDaCor')
self.log(message, level=logging.DEBUG, name="MoDaCor")
16 changes: 11 additions & 5 deletions src/modacor/dataclasses/process_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

__all__ = ["ProcessStep"]
__license__ = "BSD-3-Clause"
__version__ = "0.0.1"


from abc import abstractmethod
from numbers import Integral
from pathlib import Path
from typing import Any

from attrs import define, field
Expand All @@ -26,7 +28,12 @@ class ProcessStep:
io_sources: IoSources = field()

# class attribute for a machine-readable description of the process step
documentation: ProcessStepDescriber
documentation = ProcessStepDescriber(
calling_name="Generic Process step",
calling_id=None,
calling_module_path=Path(__file__),
calling_version=__version__,
)

# dynamic instance configuration
configuration: dict = field(factory=dict, validator=v.instance_of(dict))
Expand All @@ -45,9 +52,8 @@ class ProcessStep:
default=MessageHandler(), validator=v.instance_of(MessageHandler)
)

# a list of data keys that are modified by this process
def __attrs_post_init__(self):
self.__prepared = False
# internal variables:
__prepared: bool = field(default=False, validator=v.instance_of(bool))

def prepare_execution(self):
"""
Expand Down Expand Up @@ -94,5 +100,5 @@ def modify_config(self, key: str, value: Any):
if key in self.configuration:
self.configuration[key] = value
else:
raise KeyError(f"Key {key} not found in configuration")
raise KeyError(f"Key {key} not found in configuration") # noqa
self.__prepared = False
4 changes: 2 additions & 2 deletions src/modacor/dataclasses/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from numbers import Integral
from typing import Any
from typing import Any, Type

import pint

Expand All @@ -19,7 +19,7 @@
]


def is_list_of_ints(value: Any):
def is_list_of_ints(instance: Type, attribute: str, value: Any):
"""
Check if the value is a list of integers.
"""
Expand Down
4 changes: 0 additions & 4 deletions src/modacor/io/hdf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,3 @@
__license__ = "BSD-3-Clause"
__copyright__ = "Copyright 2025 MoDaCor Authors"
__status__ = "Alpha"


from ..io_source import IoSource
from ..io_sources import IoSources
2 changes: 1 addition & 1 deletion src/modacor/math/variance_calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@ def divide(x, vx, y, vy=0):
∂/∂y = -x / y^2
"""
result = x / y
dx_, dy_ = 1 / y, -x / (y ** 2)
dx_, dy_ = 1 / y, -x / (y**2)
variance = dx_**2 * vx + dy_**2 * vy
return result, variance
97 changes: 5 additions & 92 deletions src/modacor/tests/test_processstep.py
Original file line number Diff line number Diff line change
@@ -1,99 +1,12 @@
from datetime import datetime, timedelta, timezone
from pathlib import Path
from modacor.dataclasses.process_step import ProcessStep
from modacor.io import IoSources

import pytest

from ..dataclasses.process_step import ProcessStep


# Dummy BaseData for testing execute() since ProcessStep.execute() requires it.
class DummyBaseData:
pass
TEST_IO_SOURCES = IoSources()


def test_minimal_instantiation():
"""
Test that a ProcessStep can be instantiated with only the minimal arguments.
"""
ps = ProcessStep(
calling_name="Test Process",
calling_id="proc_001",
calling_module_path=Path("src/modacor/modules/some_module.py"),
calling_version="1.0",
)
assert ps is not None


def test_full_instantiation():
"""
Test that a ProcessStep can be instantiated with all arguments.
"""
ps = ProcessStep(
calling_name="Test Process",
calling_id="proc_002",
calling_module_path=Path("src/modacor/modules/some_module.py"),
calling_version="1.0",
required_data_keys=["fish", "cake"],
calling_arguments={"fish": "salmon", "cake": "chocolate"},
step_keywords=["test", "full"],
step_doc="Test full instantiation",
step_reference="doi: 10.1234/5678",
step_note="I am a note.",
# produced_values={}, # this is internally generated
use_frames_cache=["fish"],
use_overall_cache=["cake"],
saved={"cake": "/path/to/cake"},
)
ps.start()
ps.stop()
assert ps is not None


def test_missing_required_input():
"""
Test that a ProcessStep can be instantiated with all arguments.
"""
with pytest.raises(
ValueError, match=r"Missing required data keys in calling_arguments: ['bread']"
):
ProcessStep(
calling_name="Test Process",
calling_id="proc_002",
calling_module_path=Path("src/modacor/modules/some_module.py"),
calling_version="1.0",
required_data_keys=["fish", "cake", "bread"],
calling_arguments={"fish": "salmon", "cake": "chocolate"},
step_keywords=["test", "full"],
step_doc="Test full instantiation",
step_reference="doi: 10.1234/5678",
step_note="I am a note.",
# produced_values={}, # this is internally generated
use_frames_cache=["fish"],
use_overall_cache=["cake"],
saved={"cake": "/path/to/cake"},
)


def test_duration_calculation():
"""
Test that the duration property correctly computes elapsed time.
"""
ps = ProcessStep(
calling_name="Test Process",
calling_id="proc_003",
calling_module_path=Path("src/modacor/modules/some_module.py"),
calling_version="1.0",
required_data_keys=[],
calling_arguments={},
step_keywords=["test", "duration"],
step_doc="Test duration calculation",
step_reference="",
step_note=None,
produced_values={},
use_frames_cache=[],
)
# Manually set start_time 5 seconds before now.
ps.start_time = datetime.now(timezone.utc) - timedelta(seconds=5)
ps.stop() # Sets stop_time to now.
duration = ps.duration
assert duration is not None and duration >= 5
ps = ProcessStep(TEST_IO_SOURCES)
assert isinstance(ps, ProcessStep)
14 changes: 9 additions & 5 deletions src/modacor/tests/test_variance_calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@
`uncertainties` package. Randomly generated arrays simulate real-world numeric data
with associated variances.
"""

import numpy as np
from uncertainties.unumpy import nominal_values, std_devs, uarray

import modacor.math.variance_calculations as varc
from uncertainties.unumpy import uarray, nominal_values, std_devs

samples = 1000


def generate_samples(size, low=1, high=1.0e9):
return np.random.uniform(low, high, size)


def generate_error(values, add_zero_errors=False):
s = np.sqrt(values)
if add_zero_errors: # to check if scalars will work
Expand All @@ -35,7 +39,7 @@ def test_add():
result, variances = varc.add(x, dx**2, y, dy**2)

assert np.allclose(result, nominal_values(expected))
assert np.allclose(variances, std_devs(expected)**2)
assert np.allclose(variances, std_devs(expected) ** 2)


def test_subtract():
Expand All @@ -51,7 +55,7 @@ def test_subtract():
result, variances = varc.subtract(x, dx**2, y, dy**2)

assert np.allclose(result, nominal_values(expected))
assert np.allclose(variances, std_devs(expected)**2)
assert np.allclose(variances, std_devs(expected) ** 2)


def test_multiply():
Expand All @@ -67,7 +71,7 @@ def test_multiply():
result, variances = varc.multiply(x, dx**2, y, dy**2)

assert np.allclose(result, nominal_values(expected))
assert np.allclose(variances, std_devs(expected)**2)
assert np.allclose(variances, std_devs(expected) ** 2)


def test_divide():
Expand All @@ -83,4 +87,4 @@ def test_divide():
result, variances = varc.divide(x, dx**2, y, dy**2)

assert np.allclose(result, nominal_values(expected))
assert np.allclose(variances, std_devs(expected)**2)
assert np.allclose(variances, std_devs(expected) ** 2)
Loading