From 0c2c321266e94f6ca487084d2dd7e50b91f6ffde Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 30 Jul 2024 13:02:15 -0400 Subject: [PATCH 01/14] Adding logger, and test for get_logger --- src/wristpy/core/config.py | 21 +++++++++++++++++++++ tests/unit/test_logger.py | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/unit/test_logger.py diff --git a/src/wristpy/core/config.py b/src/wristpy/core/config.py index 2aa8df8b..45d3d01d 100644 --- a/src/wristpy/core/config.py +++ b/src/wristpy/core/config.py @@ -1,5 +1,7 @@ """Configuration module for wristpy.""" +import logging + import pydantic_settings @@ -9,3 +11,22 @@ class Settings(pydantic_settings.BaseSettings): LIGHT_THRESHOLD: float = 0.03 MODERATE_THRESHOLD: float = 0.1 VIGOROUS_THRESHOLD: float = 0.3 + + LOGGING_VERBOSITY: int = 20 + + +def get_logger() -> logging.Logger: + """Gets the wristpy logger.""" + if logging.getLogger("wristpy").hasHandlers(): + return logging.getLogger("wristpy") + logger = logging.getLogger("wristpy") + logger.setLevel(Settings().LOGGING_VERBOSITY) + + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)s - %(funcName)s - %(message)s", # noqa: E501 + ) + + handler = logging.StreamHandler() + handler.setFormatter(formatter) + logger.addHandler(handler) + return logger diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py new file mode 100644 index 00000000..43455bd8 --- /dev/null +++ b/tests/unit/test_logger.py @@ -0,0 +1,22 @@ +"""Test logging in config.py.""" + +import pytest + +from wristpy.core import config + +logger = config.get_logger() + + +def test_get_logger(caplog: pytest.LogCaptureFixture) -> None: + """Test the wristpy logger with level set to 20 (info).""" + caplog.set_level(config.Settings().LOGGING_VERBOSITY) + logger = config.get_logger() + + logger.debug("Debug message here.") + logger.info("Info message here.") + logger.warning("Warning message here") + + assert logger.getEffectiveLevel() == 20 + assert "Debug message here" not in caplog.text + assert "Info message here" in caplog.text + assert "Warning message here" in caplog.text From bf31e19e3ce35b842ef01b1f89c7fb6f4a450e80 Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 30 Jul 2024 13:04:15 -0400 Subject: [PATCH 02/14] typos --- tests/unit/test_logger.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py index 43455bd8..637ece7f 100644 --- a/tests/unit/test_logger.py +++ b/tests/unit/test_logger.py @@ -14,9 +14,9 @@ def test_get_logger(caplog: pytest.LogCaptureFixture) -> None: logger.debug("Debug message here.") logger.info("Info message here.") - logger.warning("Warning message here") + logger.warning("Warning message here.") assert logger.getEffectiveLevel() == 20 assert "Debug message here" not in caplog.text - assert "Info message here" in caplog.text - assert "Warning message here" in caplog.text + assert "Info message here." in caplog.text + assert "Warning message here." in caplog.text From cf7f7213d33c644746a7dc4451bedd1529bce444 Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:03:48 -0400 Subject: [PATCH 03/14] duplicate line. --- tests/unit/test_logger.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py index 637ece7f..908de3a4 100644 --- a/tests/unit/test_logger.py +++ b/tests/unit/test_logger.py @@ -4,8 +4,6 @@ from wristpy.core import config -logger = config.get_logger() - def test_get_logger(caplog: pytest.LogCaptureFixture) -> None: """Test the wristpy logger with level set to 20 (info).""" From 5a0820d64bd08dc1d4806d66178e208012a79b8b Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:05:09 -0400 Subject: [PATCH 04/14] var name change --- src/wristpy/core/config.py | 4 ++-- tests/unit/test_logger.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wristpy/core/config.py b/src/wristpy/core/config.py index 45d3d01d..abf26e16 100644 --- a/src/wristpy/core/config.py +++ b/src/wristpy/core/config.py @@ -12,7 +12,7 @@ class Settings(pydantic_settings.BaseSettings): MODERATE_THRESHOLD: float = 0.1 VIGOROUS_THRESHOLD: float = 0.3 - LOGGING_VERBOSITY: int = 20 + LOGGING_LEVEL: int = 20 def get_logger() -> logging.Logger: @@ -20,7 +20,7 @@ def get_logger() -> logging.Logger: if logging.getLogger("wristpy").hasHandlers(): return logging.getLogger("wristpy") logger = logging.getLogger("wristpy") - logger.setLevel(Settings().LOGGING_VERBOSITY) + logger.setLevel(Settings().LOGGING_LEVEL) formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)s - %(funcName)s - %(message)s", # noqa: E501 diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py index 908de3a4..f5c17f4e 100644 --- a/tests/unit/test_logger.py +++ b/tests/unit/test_logger.py @@ -7,7 +7,7 @@ def test_get_logger(caplog: pytest.LogCaptureFixture) -> None: """Test the wristpy logger with level set to 20 (info).""" - caplog.set_level(config.Settings().LOGGING_VERBOSITY) + caplog.set_level(config.Settings().LOGGING_LEVEL) logger = config.get_logger() logger.debug("Debug message here.") From b8d3c73c64ee3d7bbc236905c75826cdb74c66c3 Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 30 Jul 2024 15:29:50 -0400 Subject: [PATCH 05/14] work around for .hasHandlers() issue. --- src/wristpy/core/config.py | 6 +++--- tests/unit/test_logger.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/wristpy/core/config.py b/src/wristpy/core/config.py index abf26e16..40b19787 100644 --- a/src/wristpy/core/config.py +++ b/src/wristpy/core/config.py @@ -17,11 +17,11 @@ class Settings(pydantic_settings.BaseSettings): def get_logger() -> logging.Logger: """Gets the wristpy logger.""" - if logging.getLogger("wristpy").hasHandlers(): - return logging.getLogger("wristpy") logger = logging.getLogger("wristpy") - logger.setLevel(Settings().LOGGING_LEVEL) + if logger.handlers: + return logger + logger.setLevel(Settings().LOGGING_LEVEL) formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)s - %(funcName)s - %(message)s", # noqa: E501 ) diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py index f5c17f4e..454abe54 100644 --- a/tests/unit/test_logger.py +++ b/tests/unit/test_logger.py @@ -7,7 +7,6 @@ def test_get_logger(caplog: pytest.LogCaptureFixture) -> None: """Test the wristpy logger with level set to 20 (info).""" - caplog.set_level(config.Settings().LOGGING_LEVEL) logger = config.get_logger() logger.debug("Debug message here.") From 6e2e9a90625291c1069e09cf2fe0e3dacdd10ae9 Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Thu, 1 Aug 2024 11:52:17 -0400 Subject: [PATCH 06/14] Added second test to hit first return statement. --- tests/unit/test_logger.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py index 454abe54..a0790a5d 100644 --- a/tests/unit/test_logger.py +++ b/tests/unit/test_logger.py @@ -17,3 +17,13 @@ def test_get_logger(caplog: pytest.LogCaptureFixture) -> None: assert "Debug message here" not in caplog.text assert "Info message here." in caplog.text assert "Warning message here." in caplog.text + + +def test_get_logger_second_call() -> None: + """Test get logger when a handler already exists.""" + logger = config.get_logger() + second_logger = config.get_logger() + + assert len(logger.handlers) == len(second_logger.handlers) == 1 + assert logger.handlers[0] is second_logger.handlers[0] + assert logger is second_logger From 4eba6c86709c0bceffaf1174125f0e8904eae29f Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:16:56 -0400 Subject: [PATCH 07/14] added log to calibraiton. --- src/wristpy/processing/calibration.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/wristpy/processing/calibration.py b/src/wristpy/processing/calibration.py index d6424ba2..13054799 100644 --- a/src/wristpy/processing/calibration.py +++ b/src/wristpy/processing/calibration.py @@ -11,7 +11,9 @@ from sklearn import linear_model from sklearn import metrics as sklearn_metrics -from wristpy.core import computations, models +from wristpy.core import computations, config, models + +logger = config.get_logger() class SphereCriteriaError(Exception): @@ -409,7 +411,8 @@ def _closest_point_fit(self, no_motion_data: np.ndarray) -> LinearTransformation weights = np.minimum( 1 / np.linalg.norm(current - closest_point, axis=1), 100 ) - + logger.debug(f"scale: {scale}, offset: {offset}") + logger.debug(f"residual: {residual}") if abs(residual - previous_residual) < self.error_tolerance: break From 3715187b635851bc376b4f9f402e1e346864569c Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:30:03 -0400 Subject: [PATCH 08/14] Adding logs --- src/wristpy/processing/analytics.py | 3 +++ src/wristpy/processing/calibration.py | 28 ++++++++++++++++++++++----- src/wristpy/processing/metrics.py | 9 ++++++++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/wristpy/processing/analytics.py b/src/wristpy/processing/analytics.py index 2ffe97c5..7443f19c 100644 --- a/src/wristpy/processing/analytics.py +++ b/src/wristpy/processing/analytics.py @@ -15,6 +15,8 @@ MODERATE_THRESHOLD = settings.MODERATE_THRESHOLD VIGOROUS_THRESHOLD = settings.VIGOROUS_THRESHOLD +logger = config.get_logger() + @dataclass class SleepWindow: @@ -83,6 +85,7 @@ def run_sleep_detection(self) -> List[SleepWindow]: A list of SleepWindow instances, each instance contains a sleep onset/wakeup time pair. """ + logger.debug("Beginning sleep detection.") spt_window = self._spt_window(self.anglez) sib_periods = self._calculate_sib_periods(self.anglez) spt_window_periods = self._find_periods(spt_window) diff --git a/src/wristpy/processing/calibration.py b/src/wristpy/processing/calibration.py index 13054799..4a3402a5 100644 --- a/src/wristpy/processing/calibration.py +++ b/src/wristpy/processing/calibration.py @@ -16,25 +16,38 @@ logger = config.get_logger() -class SphereCriteriaError(Exception): +class LoggedException(Exception): + """Base class that automatically logs messages.""" + + def __init__(self, message: str) -> None: + """Initialize a new instance of the LoggedException class. + + Args: + message: The message to display. + """ + logger.exception(message) + super().__init__(message) + + +class SphereCriteriaError(LoggedException): """Data did not meet the sphere criteria.""" pass -class CalibrationError(Exception): +class CalibrationError(LoggedException): """Was not able to lower calibration below error threshold.""" pass -class NoMotionError(Exception): +class NoMotionError(LoggedException): """No epochs with zero movement could be found in the data.""" pass -class ZeroScaleError(Exception): +class ZeroScaleError(LoggedException): """Scale value went to zero.""" pass @@ -203,6 +216,7 @@ def _chunked_calibration( CalibrationError: If all possible chunks have been used and the calibration process fails to get below the `min_calibration_error` threshold. """ + logger.debug("running chunked calibration.") for chunk in self._get_chunk(acceleration): try: return self._calibrate(chunk) @@ -224,6 +238,7 @@ def _get_chunk( everytime the generator function is called. """ + logger.debug("Getting chunk.") sampling_rate = Calibration._get_sampling_rate(timestamps=acceleration.time) min_samples = int(self.min_calibration_hours * 3600 * sampling_rate) chunk_size = int(12 * 3600 * sampling_rate) @@ -273,6 +288,7 @@ def _calibrate(self, acceleration: models.Measurement) -> LinearTransformation: and temperature: an evaluation on four continents. J Appl Physiol (1985) 2014 Oct 1;117(7):738-44. doi: 10.1152/japplphysiol.00421.2014. """ + logger.debug("attempting calibration...") no_motion_data = self._extract_no_motion(acceleration=acceleration) linear_transformation = self._closest_point_fit(no_motion_data=no_motion_data) @@ -295,7 +311,7 @@ def _calibrate(self, acceleration: models.Measurement) -> LinearTransformation: f"Initial Error: {cal_error_initial}, Final Error: {cal_error_end}," f"Error threshold: {self.min_calibration_error}" ) - + logger.debug("Calibration successful, returning scale and offset values.") return linear_transformation def _extract_no_motion(self, acceleration: models.Measurement) -> np.ndarray: @@ -326,6 +342,7 @@ def _extract_no_motion(self, acceleration: models.Measurement) -> np.ndarray: and temperature: an evaluation on four continents. J Appl Physiol (1985) 2014 Oct 1;117(7):738-44. doi: 10.1152/japplphysiol.00421.2014. """ + logger.debug("extracting no motion.") moving_sd = computations.moving_std(acceleration, 10) moving_mean = computations.moving_mean(acceleration, 10) no_motion_check = np.all( @@ -373,6 +390,7 @@ def _closest_point_fit(self, no_motion_data: np.ndarray) -> LinearTransformation and temperature: an evaluation on four continents. J Appl Physiol (1985) 2014 Oct 1;117(7):738-44. doi: 10.1152/japplphysiol.00421.2014. """ + logger.debug("Beginning closest point fit.") sphere_criteria_check = np.all( (no_motion_data.min(axis=0) < -self.min_acceleration) & (no_motion_data.max(axis=0) > self.min_acceleration) diff --git a/src/wristpy/processing/metrics.py b/src/wristpy/processing/metrics.py index 8628b2dd..962f929a 100644 --- a/src/wristpy/processing/metrics.py +++ b/src/wristpy/processing/metrics.py @@ -3,7 +3,9 @@ import numpy as np import polars as pl -from wristpy.core import models +from wristpy.core import config, models + +logger = config.get_logger() def euclidean_norm_minus_one(acceleration: models.Measurement) -> models.Measurement: @@ -93,6 +95,7 @@ def detect_nonwear( Returns: A new Measurment instance with the non-wear flag and corresponding timestamps. """ + logger.debug("Detecting non-wear data.") acceleration_grouped_by_short_window = _group_acceleration_data_by_time( acceleration, short_epoch_length ) @@ -109,6 +112,10 @@ def detect_nonwear( ) non_wear_flag = np.where(nonwear_value_array_cleaned >= 2, 1, 0) + logger.debug( + f"Returning non-wear array of length {len(non_wear_flag)},", + f"time stamps of length {len(acceleration_grouped_by_short_window["time"])}", + ) return models.Measurement( measurements=non_wear_flag, time=acceleration_grouped_by_short_window["time"] ) From 8b1b13e91a2c6ea3e8614aae44a2254211e52f8c Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Wed, 28 Aug 2024 17:25:09 -0400 Subject: [PATCH 09/14] logs for sleep --- src/wristpy/processing/analytics.py | 13 ++++++++++--- src/wristpy/processing/metrics.py | 4 ---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/wristpy/processing/analytics.py b/src/wristpy/processing/analytics.py index 34d8248d..2724b37c 100644 --- a/src/wristpy/processing/analytics.py +++ b/src/wristpy/processing/analytics.py @@ -93,7 +93,9 @@ def run_sleep_detection(self) -> List[SleepWindow]: sleep_onset_wakeup = self._find_onset_wakeup_times( spt_window_periods, sib_window_periods ) - + logger.debug( + f"Sleep detection complete. Windows detected: {len(sleep_onset_wakeup)}" + ) return sleep_onset_wakeup def _spt_window( @@ -123,6 +125,7 @@ def _spt_window( using an accelerometer without sleep diary. Sci Rep 8, 12975 (2018). https://doi.org/10.1038/s41598-018-31266-z """ + logger.debug(f"Finding spt windows, Threshold: {threshold}") long_epoch_median = 300 long_block = 360 short_block_gap = 720 @@ -142,7 +145,7 @@ def _spt_window( sleep_idx_array_filled = self._fill_false_blocks( sleep_candidates, short_block_gap ) - + logger.debug("Found SPT windows") return models.Measurement( measurements=sleep_idx_array_filled, time=anglez_median_long_epoch.time ) @@ -314,6 +317,7 @@ def _find_periods( a period. For isolated ones the function returns the same start and end time. The list is sorted by time. """ + logger.debug("Finding periods.") edge_detection = np.convolve([1, 3, 1], window_measurement.measurements, "same") single_one = np.nonzero(edge_detection == 3)[0] @@ -403,8 +407,11 @@ def compute_physical_activty_categories( Raises: ValueError: If the threshold values are not in ascending order. """ + logger.debug(f"Computing physical activity levels, thresholds: {thresholds}") if list(thresholds) != sorted(thresholds): - raise ValueError("Thresholds must be in ascending order.") + message = "Thresholds must be in ascending order." + logger.error("ValueError, thresholds must be in ascending order.") + raise ValueError(message) activity_levels = ( ( diff --git a/src/wristpy/processing/metrics.py b/src/wristpy/processing/metrics.py index 962f929a..be44459d 100644 --- a/src/wristpy/processing/metrics.py +++ b/src/wristpy/processing/metrics.py @@ -112,10 +112,6 @@ def detect_nonwear( ) non_wear_flag = np.where(nonwear_value_array_cleaned >= 2, 1, 0) - logger.debug( - f"Returning non-wear array of length {len(non_wear_flag)},", - f"time stamps of length {len(acceleration_grouped_by_short_window["time"])}", - ) return models.Measurement( measurements=non_wear_flag, time=acceleration_grouped_by_short_window["time"] ) From a6cb3a89ea5e6b2d17069cfbb8e5e0c483a9b1ae Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Thu, 29 Aug 2024 11:20:32 -0400 Subject: [PATCH 10/14] more logs for calibration and analytics --- src/wristpy/processing/analytics.py | 15 +++++++++++---- src/wristpy/processing/calibration.py | 14 ++++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/wristpy/processing/analytics.py b/src/wristpy/processing/analytics.py index 2724b37c..a59e341d 100644 --- a/src/wristpy/processing/analytics.py +++ b/src/wristpy/processing/analytics.py @@ -145,7 +145,6 @@ def _spt_window( sleep_idx_array_filled = self._fill_false_blocks( sleep_candidates, short_block_gap ) - logger.debug("Found SPT windows") return models.Measurement( measurements=sleep_idx_array_filled, time=anglez_median_long_epoch.time ) @@ -172,6 +171,7 @@ def _calculate_sib_periods( Duration Using a Wrist-Worn Accelerometer. PLoS One 10, e0142533 (2015). https://doi.org/10.1371/journal.pone.0142533 """ + logger.debug(f"Calculating SIB period threshold: {threshold_degrees} degrees") anglez_abs_diff = self._compute_abs_diff_mean_anglez(anglez_data) anglez_pl_df = pl.DataFrame( @@ -220,6 +220,11 @@ def _find_onset_wakeup_times( If there is no overlap between spt_windows and sib_periods, the onset and wakeup lists will be empty. """ + logger.debug( + "Searching for SIB periods within SPT windows." + f"SPT periods: {len(spt_periods)}," + f"SIB periods: {len(sib_periods)}" + ) sleep_windows = [] for sleep_guide in spt_periods: min_onset = None @@ -235,7 +240,7 @@ def _find_onset_wakeup_times( max_wakeup = inactivity_bout[1] if min_onset is not None and max_wakeup is not None: sleep_windows.append(SleepWindow(onset=min_onset, wakeup=max_wakeup)) - + logger.debug(f"{sleep_windows} sleep windows found.") return sleep_windows def _fill_false_blocks( @@ -317,7 +322,7 @@ def _find_periods( a period. For isolated ones the function returns the same start and end time. The list is sorted by time. """ - logger.debug("Finding periods.") + logger.debug("Finding periods in window measurement.") edge_detection = np.convolve([1, 3, 1], window_measurement.measurements, "same") single_one = np.nonzero(edge_detection == 3)[0] @@ -335,6 +340,7 @@ def _find_periods( all_periods = single_periods + block_periods all_periods.sort() + logger.debug(f"Found {len(all_periods)} periods.") return all_periods @@ -356,6 +362,7 @@ def remove_nonwear_from_sleep( Returns: A List of the filtered sleep windows. """ + logger.debug(f"Finding non-wear periods within {len(sleep_windows)} sleep windows.") nonwear_periods = _find_periods(non_wear_array) filtered_sleep_windows = [] @@ -376,6 +383,7 @@ def remove_nonwear_from_sleep( ): filtered_sleep_windows.append(sleep_window) + logger.debug(f"Non-wear removed. {len(sleep_windows)} sleep windows remain.") return filtered_sleep_windows @@ -426,5 +434,4 @@ def compute_physical_activty_categories( * 2 + (enmo_epoch1.measurements > thresholds[2]) * 3 ) - return models.Measurement(measurements=activity_levels, time=enmo_epoch1.time) diff --git a/src/wristpy/processing/calibration.py b/src/wristpy/processing/calibration.py index 4a3402a5..0576ac7e 100644 --- a/src/wristpy/processing/calibration.py +++ b/src/wristpy/processing/calibration.py @@ -170,6 +170,7 @@ def run(self, acceleration: models.Measurement) -> models.Measurement: CalibrationError: If the calibration process fails to get below the `min_calibration_error` threshold. """ + logger.debug("Starting calibration.") data_range = cast(datetime, acceleration.time.max()) - cast( datetime, acceleration.time.min() ) @@ -288,7 +289,7 @@ def _calibrate(self, acceleration: models.Measurement) -> LinearTransformation: and temperature: an evaluation on four continents. J Appl Physiol (1985) 2014 Oct 1;117(7):738-44. doi: 10.1152/japplphysiol.00421.2014. """ - logger.debug("attempting calibration...") + logger.debug("attempting to calibrate...") no_motion_data = self._extract_no_motion(acceleration=acceleration) linear_transformation = self._closest_point_fit(no_motion_data=no_motion_data) @@ -311,7 +312,11 @@ def _calibrate(self, acceleration: models.Measurement) -> LinearTransformation: f"Initial Error: {cal_error_initial}, Final Error: {cal_error_end}," f"Error threshold: {self.min_calibration_error}" ) - logger.debug("Calibration successful, returning scale and offset values.") + logger.debug( + "Calibration successful.", + f"scale: {linear_transformation.scale}.", + f"Offset: {linear_transformation.offset}.", + ) return linear_transformation def _extract_no_motion(self, acceleration: models.Measurement) -> np.ndarray: @@ -429,9 +434,10 @@ def _closest_point_fit(self, no_motion_data: np.ndarray) -> LinearTransformation weights = np.minimum( 1 / np.linalg.norm(current - closest_point, axis=1), 100 ) - logger.debug(f"scale: {scale}, offset: {offset}") - logger.debug(f"residual: {residual}") + + logger.debug(f"scale: {scale}, offset: {offset}, residual: {residual}") if abs(residual - previous_residual) < self.error_tolerance: + logger.debug("Change in residual below error tolerance, ending loop.}") break previous_residual = residual From a18667aa185109fe690e35bd5eca5401007de8d4 Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 3 Sep 2024 08:54:05 -0400 Subject: [PATCH 11/14] Fixing capitalizations, changed f-strings to arg formatting. --- src/wristpy/processing/analytics.py | 27 ++++++++++++++------------- src/wristpy/processing/calibration.py | 18 +++++++++--------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/wristpy/processing/analytics.py b/src/wristpy/processing/analytics.py index a59e341d..aff8bc6a 100644 --- a/src/wristpy/processing/analytics.py +++ b/src/wristpy/processing/analytics.py @@ -94,7 +94,7 @@ def run_sleep_detection(self) -> List[SleepWindow]: spt_window_periods, sib_window_periods ) logger.debug( - f"Sleep detection complete. Windows detected: {len(sleep_onset_wakeup)}" + "Sleep detection complete. Windows detected: %s", len(sleep_onset_wakeup) ) return sleep_onset_wakeup @@ -125,7 +125,7 @@ def _spt_window( using an accelerometer without sleep diary. Sci Rep 8, 12975 (2018). https://doi.org/10.1038/s41598-018-31266-z """ - logger.debug(f"Finding spt windows, Threshold: {threshold}") + logger.debug("Finding spt windows, Threshold: %s", threshold) long_epoch_median = 300 long_block = 360 short_block_gap = 720 @@ -171,7 +171,7 @@ def _calculate_sib_periods( Duration Using a Wrist-Worn Accelerometer. PLoS One 10, e0142533 (2015). https://doi.org/10.1371/journal.pone.0142533 """ - logger.debug(f"Calculating SIB period threshold: {threshold_degrees} degrees") + logger.debug("Calculating SIB period threshold: %s degrees", threshold_degrees) anglez_abs_diff = self._compute_abs_diff_mean_anglez(anglez_data) anglez_pl_df = pl.DataFrame( @@ -221,9 +221,9 @@ def _find_onset_wakeup_times( the onset and wakeup lists will be empty. """ logger.debug( - "Searching for SIB periods within SPT windows." - f"SPT periods: {len(spt_periods)}," - f"SIB periods: {len(sib_periods)}" + "Finding SIB periods within SPT windows. SPT periods:%s, SIB periods: %s", + spt_periods, + sib_periods, ) sleep_windows = [] for sleep_guide in spt_periods: @@ -240,7 +240,7 @@ def _find_onset_wakeup_times( max_wakeup = inactivity_bout[1] if min_onset is not None and max_wakeup is not None: sleep_windows.append(SleepWindow(onset=min_onset, wakeup=max_wakeup)) - logger.debug(f"{sleep_windows} sleep windows found.") + logger.debug("Sleep windows found: %s", len(sleep_windows)) return sleep_windows def _fill_false_blocks( @@ -340,7 +340,7 @@ def _find_periods( all_periods = single_periods + block_periods all_periods.sort() - logger.debug(f"Found {len(all_periods)} periods.") + logger.debug("Found %s periods.", len(all_periods)) return all_periods @@ -362,7 +362,9 @@ def remove_nonwear_from_sleep( Returns: A List of the filtered sleep windows. """ - logger.debug(f"Finding non-wear periods within {len(sleep_windows)} sleep windows.") + logger.debug( + "Finding non-wear periods within %s sleep windows.", len(sleep_windows) + ) nonwear_periods = _find_periods(non_wear_array) filtered_sleep_windows = [] @@ -383,7 +385,7 @@ def remove_nonwear_from_sleep( ): filtered_sleep_windows.append(sleep_window) - logger.debug(f"Non-wear removed. {len(sleep_windows)} sleep windows remain.") + logger.debug("Non-wear removed. %s sleep windows remain.", len(sleep_windows)) return filtered_sleep_windows @@ -415,11 +417,10 @@ def compute_physical_activty_categories( Raises: ValueError: If the threshold values are not in ascending order. """ - logger.debug(f"Computing physical activity levels, thresholds: {thresholds}") + logger.debug("Computing physical activity levels, thresholds: %s", thresholds) if list(thresholds) != sorted(thresholds): - message = "Thresholds must be in ascending order." logger.error("ValueError, thresholds must be in ascending order.") - raise ValueError(message) + raise ValueError("Thresholds must be in ascending order.") activity_levels = ( ( diff --git a/src/wristpy/processing/calibration.py b/src/wristpy/processing/calibration.py index 0576ac7e..a6ef0f56 100644 --- a/src/wristpy/processing/calibration.py +++ b/src/wristpy/processing/calibration.py @@ -217,7 +217,7 @@ def _chunked_calibration( CalibrationError: If all possible chunks have been used and the calibration process fails to get below the `min_calibration_error` threshold. """ - logger.debug("running chunked calibration.") + logger.debug("Running chunked calibration.") for chunk in self._get_chunk(acceleration): try: return self._calibrate(chunk) @@ -289,7 +289,7 @@ def _calibrate(self, acceleration: models.Measurement) -> LinearTransformation: and temperature: an evaluation on four continents. J Appl Physiol (1985) 2014 Oct 1;117(7):738-44. doi: 10.1152/japplphysiol.00421.2014. """ - logger.debug("attempting to calibrate...") + logger.debug("Attempting to calibrate...") no_motion_data = self._extract_no_motion(acceleration=acceleration) linear_transformation = self._closest_point_fit(no_motion_data=no_motion_data) @@ -308,14 +308,14 @@ def _calibrate(self, acceleration: models.Measurement) -> LinearTransformation: cal_error_end >= self.min_calibration_error ): raise CalibrationError( - "Calibration error could not be sufficiently minimized." - f"Initial Error: {cal_error_initial}, Final Error: {cal_error_end}," + "Calibration error could not be sufficiently minimized. " + f"Initial Error: {cal_error_initial}, Final Error: {cal_error_end}, " f"Error threshold: {self.min_calibration_error}" ) logger.debug( - "Calibration successful.", - f"scale: {linear_transformation.scale}.", - f"Offset: {linear_transformation.offset}.", + "Calibration successful. Scale: %s, Offset: %s", + linear_transformation.scale, + linear_transformation.offset, ) return linear_transformation @@ -347,7 +347,7 @@ def _extract_no_motion(self, acceleration: models.Measurement) -> np.ndarray: and temperature: an evaluation on four continents. J Appl Physiol (1985) 2014 Oct 1;117(7):738-44. doi: 10.1152/japplphysiol.00421.2014. """ - logger.debug("extracting no motion.") + logger.debug("Extracting no motion.") moving_sd = computations.moving_std(acceleration, 10) moving_mean = computations.moving_mean(acceleration, 10) no_motion_check = np.all( @@ -435,7 +435,7 @@ def _closest_point_fit(self, no_motion_data: np.ndarray) -> LinearTransformation 1 / np.linalg.norm(current - closest_point, axis=1), 100 ) - logger.debug(f"scale: {scale}, offset: {offset}, residual: {residual}") + logger.debug("Scale: %s, Offset: %s, Residual: %s", scale, offset, residual) if abs(residual - previous_residual) < self.error_tolerance: logger.debug("Change in residual below error tolerance, ending loop.}") break From 32fbb554672d33f2b222320f754598c184de35c3 Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:01:55 -0400 Subject: [PATCH 12/14] typo --- src/wristpy/core/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wristpy/core/config.py b/src/wristpy/core/config.py index 40b19787..f338d5f3 100644 --- a/src/wristpy/core/config.py +++ b/src/wristpy/core/config.py @@ -12,7 +12,7 @@ class Settings(pydantic_settings.BaseSettings): MODERATE_THRESHOLD: float = 0.1 VIGOROUS_THRESHOLD: float = 0.3 - LOGGING_LEVEL: int = 20 + LOGGING_LEVEL = logging.INFO def get_logger() -> logging.Logger: From a8d069bc62f64ed35da74f3978e19cc0ff3abb8c Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 3 Sep 2024 09:08:38 -0400 Subject: [PATCH 13/14] type annotation --- src/wristpy/core/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wristpy/core/config.py b/src/wristpy/core/config.py index f338d5f3..aa6a19c7 100644 --- a/src/wristpy/core/config.py +++ b/src/wristpy/core/config.py @@ -12,7 +12,7 @@ class Settings(pydantic_settings.BaseSettings): MODERATE_THRESHOLD: float = 0.1 VIGOROUS_THRESHOLD: float = 0.3 - LOGGING_LEVEL = logging.INFO + LOGGING_LEVEL: int = logging.INFO def get_logger() -> logging.Logger: From f3e6c10b3d3439e2bc089f7c1ce3b7f2ef6f45de Mon Sep 17 00:00:00 2001 From: frey-perez <160774979+frey-perez@users.noreply.github.com> Date: Tue, 3 Sep 2024 10:42:02 -0400 Subject: [PATCH 14/14] doc string edit. --- src/wristpy/processing/analytics.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wristpy/processing/analytics.py b/src/wristpy/processing/analytics.py index aff8bc6a..90858d21 100644 --- a/src/wristpy/processing/analytics.py +++ b/src/wristpy/processing/analytics.py @@ -363,7 +363,8 @@ def remove_nonwear_from_sleep( A List of the filtered sleep windows. """ logger.debug( - "Finding non-wear periods within %s sleep windows.", len(sleep_windows) + "Finding non-wear periods that overlap with any of the %s sleep windows.", + len(sleep_windows), ) nonwear_periods = _find_periods(non_wear_array)