From 4ebe8fddcafd1028a0daea3ee98fc0a2a6d2c206 Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Sun, 8 Feb 2026 17:32:40 -0500 Subject: [PATCH 1/9] updating typing --- src/fasttrackpy/patterns/audio_textgrid.py | 11 ++++++----- src/fasttrackpy/patterns/corpus.py | 12 +++++++----- src/fasttrackpy/patterns/just_audio.py | 7 +++---- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/fasttrackpy/patterns/audio_textgrid.py b/src/fasttrackpy/patterns/audio_textgrid.py index 2162e77..0fcc872 100644 --- a/src/fasttrackpy/patterns/audio_textgrid.py +++ b/src/fasttrackpy/patterns/audio_textgrid.py @@ -1,3 +1,4 @@ +from collections.abc import Sequence import parselmouth as pm from aligned_textgrid import AlignedTextGrid, Word, Phone, SequenceInterval, SequenceTier import aligned_textgrid @@ -66,7 +67,7 @@ def get_candidates(args_dict): @delayed @safely(message="There was a problem getting some candidate tracks.") -def get_candidates_delayed(args_dict): +def get_candidates_delayed(args_dict) -> CandidateTracks: with warnings.catch_warnings(): warnings.simplefilter("ignore") candidates = CandidateTracks(**args_dict) @@ -74,10 +75,10 @@ def get_candidates_delayed(args_dict): warnings.warn("formant tracking error") return candidates -def run_candidates(arg_list, parallel:bool): +def run_candidates(arg_list, parallel:bool) -> Sequence[CandidateTracks]: if parallel: n_jobs = cpu_count() - all_candidates = Parallel(n_jobs=n_jobs)( + all_candidates = Parallel(n_jobs=n_jobs, return_as="list")( get_candidates_delayed(args_dict=arg) for arg in tqdm(arg_list) ) return all_candidates @@ -104,7 +105,7 @@ def process_audio_textgrid( loss_fun: Loss = Loss(), agg_fun: Agg = Agg(), heuristics: list[MinMaxHeuristic|SpacingHeuristic] = [] -)->list[CandidateTracks]: +)->Sequence[CandidateTracks]: """Process an audio and TextGrid file together. Args: @@ -154,7 +155,7 @@ def process_audio_textgrid( entry_classes = get_interval_classes(textgrid_format=entry_classes) - tg = AlignedTextGrid(textgrid_path=textgrid_path, entry_classes=entry_classes) + tg = AlignedTextGrid(textgrid=textgrid_path, entry_classes=entry_classes) target_tiers = get_target_tiers(tg, target_tier=target_tier) target_intervals = get_target_intervals( target_tiers=target_tiers, diff --git a/src/fasttrackpy/patterns/corpus.py b/src/fasttrackpy/patterns/corpus.py index 59e2895..a4ed30b 100644 --- a/src/fasttrackpy/patterns/corpus.py +++ b/src/fasttrackpy/patterns/corpus.py @@ -17,6 +17,8 @@ import os import sys +from collections.abc import Sequence + CorpusPair = namedtuple("CorpusPair", field_names=["wav", "tg"]) def get_audio_files( @@ -32,7 +34,7 @@ def get_audio_files( def get_corpus( audio_files:list[Path] - ) -> list[tuple[Path, Path]]: + ) -> Sequence[CorpusPair]: wav_tg = [ CorpusPair(wav, wav.with_suffix(".TextGrid")) for wav in audio_files @@ -42,7 +44,7 @@ def get_corpus( def read_and_associate_tg( corpus_pair: CorpusPair, - entry_classes:list[SequenceInterval] = [Word, Phone] + entry_classes:Sequence[type[SequenceInterval]] = [Word, Phone] ) -> AlignedTextGrid: tg = AlignedTextGrid( textgrid_path=str(corpus_pair.tg), @@ -91,8 +93,8 @@ def get_target_intervals( def get_sound_parts( intervals: list[SequenceInterval], window_length: float -): - sound = pm.Sound(str(intervals[0].wav)) +) -> Sequence[pm.Sound]: + sound = pm.Sound(str(getattr(intervals[0], "wav"))) sound_parts = [ sound.extract_part(from_time = interval.start-(window_length/2), to_time = interval.end+(window_length/2)) @@ -120,7 +122,7 @@ def get_candidates(args_dict): warnings.warn("formant tracking error") return candidates -def run_candidates(arg_list, parallel:bool): +def run_candidates(arg_list, parallel:bool) -> Sequence[CandidateTracks]: if parallel: n_jobs = cpu_count() all_candidates = Parallel(n_jobs=n_jobs)( diff --git a/src/fasttrackpy/patterns/just_audio.py b/src/fasttrackpy/patterns/just_audio.py index 402034a..5f171a2 100644 --- a/src/fasttrackpy/patterns/just_audio.py +++ b/src/fasttrackpy/patterns/just_audio.py @@ -1,7 +1,6 @@ import warnings from pathlib import Path -from typing import Union -from collections.abc import Callable +from collections.abc import Callable, Sequence import parselmouth as pm from fasttrackpy import CandidateTracks,\ Smoother,\ @@ -38,7 +37,7 @@ def is_audio(path: str|Path)->bool: def process_audio_file( path: str|Path, xmin:float = 0, - xmax: float = None, + xmax: float|None = None, min_max_formant:float = 4000, max_max_formant:float = 7000, nstep:int = 20, @@ -123,7 +122,7 @@ def get_candidates_delayed(args_dict): def get_candidates(args_dict): return process_audio_file(**args_dict) -def run_candidates(arg_list, parallel:bool): +def run_candidates(arg_list, parallel:bool) -> Sequence[CandidateTracks]: if parallel: n_jobs = cpu_count() all_candidates = Parallel(n_jobs=n_jobs)( From 78dcf25a5c6ef0ebc48d98b7173c0b43fd9d2453 Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Sun, 8 Feb 2026 17:34:47 -0500 Subject: [PATCH 2/9] update typing --- src/fasttrackpy/processors/aggs.py | 9 ++++--- src/fasttrackpy/processors/losses.py | 35 +++++++++++++------------ src/fasttrackpy/processors/smoothers.py | 12 ++++----- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/fasttrackpy/processors/aggs.py b/src/fasttrackpy/processors/aggs.py index 1ff24d6..67a22c0 100644 --- a/src/fasttrackpy/processors/aggs.py +++ b/src/fasttrackpy/processors/aggs.py @@ -1,4 +1,5 @@ import numpy as np +import numpy.typing as npt from typing import Union from collections.abc import Callable @@ -11,7 +12,7 @@ class Agg: def __init__( self, - method: Union[str, Callable]= "agg_sum", + method: str|Callable = "agg_sum", **kwargs ): self.method = self._get_method(method) @@ -19,11 +20,11 @@ def __init__( def _get_method( self, - method:Union[str, Callable] - ): + method:str|Callable[[npt.NDArray], float] + )->Callable: if callable(method): return method - if method == "agg_sum": + else: return agg_sum def aggregate( diff --git a/src/fasttrackpy/processors/losses.py b/src/fasttrackpy/processors/losses.py index df551a2..1da7248 100644 --- a/src/fasttrackpy/processors/losses.py +++ b/src/fasttrackpy/processors/losses.py @@ -1,6 +1,7 @@ import numpy as np -from typing import Union +import numpy.typing as npt from collections.abc import Callable + class Loss: """_summary_ @@ -10,7 +11,7 @@ class Loss: def __init__( self, - method: Union[str, Callable] = "lmse", + method: str|Callable = "lmse", **kwargs ): self.method = self._get_fun(method) @@ -18,13 +19,13 @@ def __init__( def _get_fun( self, - method: Union[str, Callable] + method: str|Callable ) -> Callable: if callable(method): return method - if method == "lmse": + elif method == "lmse": return lmse - if method == "mse": + else: return mse def calculate_loss( @@ -35,38 +36,38 @@ def calculate_loss( return self.method(formants, smoothed, **self.method_args) def lmse( - formants: np.ndarray, - smoothed: np.ndarray, + formants: npt.NDArray, + smoothed: npt.NDArray, axis: int = 1 - ) -> np.ndarray: + ) -> npt.NDArray: """_summary_ Args: - formants (np.ndarray): _description_ - smoothed (np.ndarray): _description_ + formants (npt.NDArray): _description_ + smoothed (npt.NDArray): _description_ axis (int, optional): _description_. Defaults to 1. Returns: - np.ndarray: _description_ + npt.NDArray: _description_ """ sqe = np.power(np.log(formants) - np.log(smoothed), 2) mse = np.nanmean(sqe, axis = axis) return mse def mse( - formants: np.ndarray, - smoothed: np.ndarray, + formants: npt.NDArray, + smoothed: npt.NDArray, axis: int = 1 - ) -> np.ndarray: + ) -> npt.NDArray: """_summary_ Args: - formants (np.ndarray): _description_ - smoothed (np.ndarray): _description_ + formants (npt.NDArray): _description_ + smoothed (npt.NDArray): _description_ axis (int, optional): _description_. Defaults to 1. Returns: - np.ndarray: _description_ + npt.NDArray: _description_ """ sqe = np.power(formants - smoothed, 2) mse = np.nanmean(sqe, axis = axis) diff --git a/src/fasttrackpy/processors/smoothers.py b/src/fasttrackpy/processors/smoothers.py index caad017..ef2537c 100644 --- a/src/fasttrackpy/processors/smoothers.py +++ b/src/fasttrackpy/processors/smoothers.py @@ -34,23 +34,23 @@ class Smoother: """ def __init__( self, - method: Union[str, Callable] = "dct_smooth_regression", + method: str|Callable = "dct_smooth_regression", **kwargs ): self.smooth_fun = self._get_fun(method) self.method_args = kwargs - def _get_fun(self, method): + def _get_fun(self, method)->Callable: if callable(method): return method - if method == "dct_smooth": + elif method == "dct_smooth": return dct_smooth - if method == "dct_smooth_regression": + else: return dct_smooth_regression def smooth( self, - x: np.array + x: npt.NDArray ) -> Smoothed: """Apply the smoother function to the data @@ -63,7 +63,7 @@ def smooth( return self.smooth_fun(x, **self.method_args) def dct_smooth( - x:np.array, + x:npt.NDArray, order:int = 5 ) -> Smoothed: """A DCT Smoother From e3dbd03300a39a91ee224fef91d18b448382af51 Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Sun, 8 Feb 2026 17:35:05 -0500 Subject: [PATCH 3/9] update typing --- src/fasttrackpy/processors/heuristic.py | 16 ++++++++-------- src/fasttrackpy/processors/outputs.py | 12 ++++-------- src/fasttrackpy/utils/safely.py | 10 +++++----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/fasttrackpy/processors/heuristic.py b/src/fasttrackpy/processors/heuristic.py index d8e216b..872463e 100644 --- a/src/fasttrackpy/processors/heuristic.py +++ b/src/fasttrackpy/processors/heuristic.py @@ -1,11 +1,12 @@ from dataclasses import dataclass, field import numpy as np +import numpy.typing as npt from collections.abc import Mapping from typing import TypeVar, TYPE_CHECKING, Literal, Annotated +from collections.abc import Sequence if TYPE_CHECKING: from fasttrackpy import OneTrack -TrackType = TypeVar("OneTrack") @dataclass class MinMaxHeuristic: @@ -40,7 +41,7 @@ class MinMaxHeuristic: number: int = 1 boundary: float|int|np.floating = 1200 - def eval(self, track: TrackType): + def eval(self, track: OneTrack): """ Evaluate whether or not the track passes the heuristic @@ -63,8 +64,7 @@ def eval(self, track: TrackType): track.log_parameters[self.number-1,0]* np.sqrt(2) ) - - if self.measure == "bandwidth": + else: mean_value = np.exp( track.bandwidth_parameters[self.number-1, 0] *np.sqrt(2) @@ -98,8 +98,8 @@ class SpacingHeuristic: bottom_diff (float|int|np.floating): The spacing of the bottom formants """ - top: list[int] = field(default_factory=lambda: [3]) - bottom: list[int] = field(default_factory=lambda: [1,2]) + top: Sequence[int]|npt.NDArray[np.int_] = field(default_factory=lambda: [3]) + bottom: Sequence[int]|npt.NDArray[np.int_] = field(default_factory=lambda: [1,2]) top_diff: float|int|np.floating = 2000 bottom_diff: float|int|np.floating = 500 @@ -107,7 +107,7 @@ def __post_init__(self): self.top = np.array(self.top) self.bottom = np.array(self.bottom) - def eval(self, track:TrackType): + def eval(self, track:OneTrack): """ Evaluate whether or not the track passes the heuriustic @@ -123,7 +123,7 @@ def eval(self, track:TrackType): """ nformants = track.n_formants - if nformants < self.top.max(): + if nformants < np.array(self.top).max(): return 0 top_values = np.array([ diff --git a/src/fasttrackpy/processors/outputs.py b/src/fasttrackpy/processors/outputs.py index 9acb8cb..c891c6a 100644 --- a/src/fasttrackpy/processors/outputs.py +++ b/src/fasttrackpy/processors/outputs.py @@ -149,8 +149,8 @@ def get_big_df(self, output): def write_data( candidates, - file: Path = None, - destination: Path = None, + file: Path|None = None, + destination: Path|None = None, which: str = "winner", output: str = "formants", separate: bool = False @@ -435,12 +435,10 @@ def pickle_candidates( The file location to save the pickle file to. """ - if type(file) is str: - file = Path(file) sys.setrecursionlimit(3000) #tmp_candidates = copy.deepcopy (candidates) - with file.open('wb') as f: + with Path(file).open('wb') as f: cloudpickle.dump(candidates, f) @@ -460,10 +458,8 @@ def unpickle_candidates( (CandidateTracks): A CandidateTracks object. """ - if type(file) is str: - file = Path(file) sys.setrecursionlimit(3000) - with file.open('rb') as f: + with Path(file).open('rb') as f: candidates = cloudpickle.load(f) return candidates diff --git a/src/fasttrackpy/utils/safely.py b/src/fasttrackpy/utils/safely.py index cb61788..3b488eb 100644 --- a/src/fasttrackpy/utils/safely.py +++ b/src/fasttrackpy/utils/safely.py @@ -1,6 +1,6 @@ import warnings -from typing import Callable -from typing import Sequence +from typing import Any +from collections.abc import Callable, Sequence def safely( @@ -28,9 +28,9 @@ def safe_func(*args, **kwargs): return decorator def filter_nones( - filterer: Sequence, - to_filter: list[Sequence] -)->list[Sequence]: + filterer: Sequence[Any], + to_filter: Sequence[Sequence[Any]] +)->Sequence[Sequence[Any]]: """ Filter lists based on the presence of None values. From 2d516c5987fea16c38e00fa8b046e5cadf1f72d7 Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Sun, 8 Feb 2026 17:44:30 -0500 Subject: [PATCH 4/9] fix typing error --- src/fasttrackpy/processors/heuristic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fasttrackpy/processors/heuristic.py b/src/fasttrackpy/processors/heuristic.py index 872463e..93fac17 100644 --- a/src/fasttrackpy/processors/heuristic.py +++ b/src/fasttrackpy/processors/heuristic.py @@ -41,7 +41,7 @@ class MinMaxHeuristic: number: int = 1 boundary: float|int|np.floating = 1200 - def eval(self, track: OneTrack): + def eval(self, track: "OneTrack"): """ Evaluate whether or not the track passes the heuristic @@ -107,7 +107,7 @@ def __post_init__(self): self.top = np.array(self.top) self.bottom = np.array(self.bottom) - def eval(self, track:OneTrack): + def eval(self, track:"OneTrack"): """ Evaluate whether or not the track passes the heuriustic From 34c34f3d0a4b737e58710fa01c96fb12564e5df6 Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Sun, 8 Feb 2026 17:47:31 -0500 Subject: [PATCH 5/9] more typing updates --- src/fasttrackpy/cli.py | 46 +++++++++++++-------------- src/fasttrackpy/processors/outputs.py | 4 +-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/fasttrackpy/cli.py b/src/fasttrackpy/cli.py index 2212cb6..3607423 100644 --- a/src/fasttrackpy/cli.py +++ b/src/fasttrackpy/cli.py @@ -39,7 +39,7 @@ "f3_f4_heuristic": F3_F4_Sep } -DEFAULT_CONFIG = str(files("fasttrackpy").joinpath("resources", "config.yml")) +DEFAULT_CONFIG = str(files("fasttrackpy").joinpath("resources").joinpath("config.yml")) logging.basicConfig( filename = "fasttrack.log", @@ -300,17 +300,17 @@ def fasttrack(): @smoother_options @heuristic_options def audio( - file: Union[str, Path] = None, - dir: Union[str,Path] = None, - output: Union[str, Path] = None, - dest: Union[str, Path] = None, + file: str|Path, + dir: str|Path, + output: str|Path, + dest: str|Path, which_output: str = "winner", data_output: str = "formants", smoother_method: str = "dct_smooth_regression", smoother_order: int = 5, loss_method: str = "lmse", xmin:float = 0, - xmax: float = None, + xmax: float|None = None, min_max_formant:float = 4000, max_max_formant:float = 7000, min_duration = 0.05, @@ -454,13 +454,13 @@ def audio( @smoother_options @heuristic_options def audio_textgrid( - audio: Union[str, Path] = None, - textgrid: Union[str,Path] = None, - entry_classes: str = None, - target_tier: str = None, - target_labels: str = None, - output: Union[str, Path] = None, - dest: Union[str, Path] = None, + audio: str|Path, + textgrid: str|Path, + entry_classes: str, + target_tier: str, + target_labels: str, + output: str|Path, + dest: str|Path, which_output: str = "winner", data_output: str = "formants", smoother_method: str = "dct_smooth_regression", @@ -533,12 +533,12 @@ def audio_textgrid( if k in heuristic_dict ] - entry_classes = entry_classes.split("|") + entry_classes_list = entry_classes.split("|") all_candidates = process_audio_textgrid( audio_path=audio, textgrid_path=textgrid, - entry_classes=entry_classes, + entry_classes=entry_classes_list, target_tier=target_tier, target_labels=target_labels, min_duration=min_duration, @@ -584,13 +584,13 @@ def audio_textgrid( @smoother_options @heuristic_options def corpus( - corpus: str|Path = None, - entry_classes: str = None, - target_tier: str = None, - target_labels: str = None, - output: str|Path = None, + corpus: str|Path, + entry_classes: str, + target_tier: str, + target_labels: str, + output: str|Path, + dest: str|Path, separate_output: bool = False, - dest: str|Path = None, which_output: str = "winner", data_output: str = "formants", smoother_method: str = "dct_smooth_regression", @@ -661,11 +661,11 @@ def corpus( if k in heuristic_dict ] - entry_classes = entry_classes.split("|") + entry_classes_list = entry_classes.split("|") all_candidates = process_corpus( corpus_path = corpus, - entry_classes = entry_classes, + entry_classes = entry_classes_list, target_tier = target_tier, target_labels = target_labels, min_duration = min_duration, diff --git a/src/fasttrackpy/processors/outputs.py b/src/fasttrackpy/processors/outputs.py index c891c6a..e746fc3 100644 --- a/src/fasttrackpy/processors/outputs.py +++ b/src/fasttrackpy/processors/outputs.py @@ -149,8 +149,8 @@ def get_big_df(self, output): def write_data( candidates, - file: Path|None = None, - destination: Path|None = None, + file: str|Path|None = None, + destination: str|Path|None = None, which: str = "winner", output: str = "formants", separate: bool = False From 7fc7995ad1d934326d22cbbe3d42f291aac2f320 Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Sun, 8 Feb 2026 17:56:58 -0500 Subject: [PATCH 6/9] finalizing typing --- src/fasttrackpy/processors/outputs.py | 4 ++-- src/fasttrackpy/tracks.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/fasttrackpy/processors/outputs.py b/src/fasttrackpy/processors/outputs.py index e746fc3..b7312b6 100644 --- a/src/fasttrackpy/processors/outputs.py +++ b/src/fasttrackpy/processors/outputs.py @@ -44,7 +44,7 @@ def add_metadata(self, out_df): return out_df -def formant_to_dataframe(self): +def formant_to_dataframe(self)->pl.DataFrame: """Return data as a data frame Returns: @@ -135,7 +135,7 @@ def log_param_to_dataframe(self): return param_df -def get_big_df(self, output): +def get_big_df(self, output) -> pl.DataFrame: all_df = [x.to_df(output = output) for x in self.candidates] all_df = [ x.with_columns( diff --git a/src/fasttrackpy/tracks.py b/src/fasttrackpy/tracks.py index b22e08e..51b2c10 100644 --- a/src/fasttrackpy/tracks.py +++ b/src/fasttrackpy/tracks.py @@ -142,9 +142,9 @@ def __init__( window_length: float = 0.025, time_step: float = 0.002, pre_emphasis_from: float = 50, - smoother: Smoother = Smoother(), - loss_fun: Loss = Loss(), - agg_fun: Agg = Agg(), + smoother: Smoother = Smoother(method="dct_smooth_regression"), + loss_fun: Loss = Loss(method = "lmse"), + agg_fun: Agg = Agg(method = "agg_sum"), heuristics: list[MinMaxHeuristic|SpacingHeuristic] = [], ): super().__init__( @@ -171,9 +171,9 @@ def __init__( self._file_name = None self._id = None self._group = None - self._formant_df = None - self._param_df = None - self._log_param_df = None + self._formant_df = pl.DataFrame() + self._param_df = pl.DataFrame() + self._log_param_df = pl.DataFrame() self._interval = None def __repr__(self): @@ -528,9 +528,9 @@ def __init__( self._id = None self._label = None self._group = None - self._formant_df = None - self._param_df = None - self._log_param_df = None + self._formant_df = pl.DataFrame() + self._param_df = pl.DataFrame() + self._log_param_df = pl.DataFrame() self._interval = None to_process = [ @@ -576,7 +576,7 @@ def __init__( self.intensity_smooth = self.smoother.smooth(self.intensity) self.intensity_log_smooth = self.smoother.smooth(np.log(self.intensity)) - def __getitem__(self, idx:int) -> OneTrack: + def __getitem__(self, idx:slice|int) -> OneTrack|Sequence[OneTrack]: return self.candidates[idx] def __len__(self) -> int: From 5fd2ce9a533763f2138b881f58f89ba3d64122be Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Mon, 9 Feb 2026 09:24:31 -0500 Subject: [PATCH 7/9] fix dataframe checking --- src/fasttrackpy/tracks.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fasttrackpy/tracks.py b/src/fasttrackpy/tracks.py index e6f0ef7..80d1458 100644 --- a/src/fasttrackpy/tracks.py +++ b/src/fasttrackpy/tracks.py @@ -356,7 +356,7 @@ def to_df( (pl.DataFrame): A `polars.DataFrame` """ if output == "formants"\ - and not isinstance(self._formant_df, pl.DataFrame): + and self._formant_df.shape == (0, 0): df = formant_to_dataframe(self) self._formant_df = df return df @@ -364,7 +364,7 @@ def to_df( return self._formant_df if output == "param"\ - and not isinstance(self._param_df, pl.DataFrame): + and self._param_df.shape == (0, 0): df = param_to_dataframe(self) self._param_df = df return df @@ -372,7 +372,7 @@ def to_df( return self._param_df if output == "log_param"\ - and not isinstance(self._log_param_df, pl.DataFrame): + and self._log_param_df.shape == (0, 0): df = log_param_to_dataframe(self) self._log_param_df = df return df @@ -691,7 +691,7 @@ def to_df( return out_df if output == "formants"\ - and not isinstance(self._formant_df, pl.DataFrame): + and self._formant_df.shape == (0, 0): big_df = get_big_df(self, output=output) self._formant_df = big_df return big_df @@ -700,7 +700,7 @@ def to_df( return self._formant_df if output == "param"\ - and not isinstance(self._param_df, pl.DataFrame): + and self._param_df.shape == (0, 0): big_df = get_big_df(self, output=output) self._param_df = big_df return big_df @@ -709,7 +709,7 @@ def to_df( return self._param_df if output == "log_param"\ - and not isinstance(self._log_param_df, pl.DataFrame): + and self._log_param_df.shape == (0, 0): big_df = get_big_df(self, output=output) self._log_param_df = big_df return big_df From 69d2722518f993f178e45defe4e3b6ac494c9ecd Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Mon, 9 Feb 2026 09:24:44 -0500 Subject: [PATCH 8/9] error in test --- tests/test_patterns/test_audio_textgrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_patterns/test_audio_textgrid.py b/tests/test_patterns/test_audio_textgrid.py index be4210b..7fafb41 100644 --- a/tests/test_patterns/test_audio_textgrid.py +++ b/tests/test_patterns/test_audio_textgrid.py @@ -69,7 +69,7 @@ def test_audio_tg2(self) : candidates = process_audio_textgrid( audio_path=AUDIO_PATH, textgrid_path=TG_PATH, - entry_classes="SequenceInterval", + entry_classes=["SequenceInterval"], target_tier="phones", target_labels="AY" ) From 6d6888683693d6cbc85fde7a2cc017ceb3cee979 Mon Sep 17 00:00:00 2001 From: JoFrhwld Date: Mon, 9 Feb 2026 09:25:05 -0500 Subject: [PATCH 9/9] final typing update --- src/fasttrackpy/patterns/audio_textgrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fasttrackpy/patterns/audio_textgrid.py b/src/fasttrackpy/patterns/audio_textgrid.py index 0fcc872..5e25773 100644 --- a/src/fasttrackpy/patterns/audio_textgrid.py +++ b/src/fasttrackpy/patterns/audio_textgrid.py @@ -104,7 +104,7 @@ def process_audio_textgrid( smoother: Smoother = Smoother(), loss_fun: Loss = Loss(), agg_fun: Agg = Agg(), - heuristics: list[MinMaxHeuristic|SpacingHeuristic] = [] + heuristics: list[MinMaxHeuristic|SpacingHeuristic|None] = [] )->Sequence[CandidateTracks]: """Process an audio and TextGrid file together.