diff --git a/resources/matteloop_de.qm b/resources/matteloop_de.qm
index 6cf020b..fcceead 100644
Binary files a/resources/matteloop_de.qm and b/resources/matteloop_de.qm differ
diff --git a/resources/matteloop_de.ts b/resources/matteloop_de.ts
index 0c6615e..fc739e7 100644
--- a/resources/matteloop_de.ts
+++ b/resources/matteloop_de.ts
@@ -118,13 +118,13 @@
-
+
Edge treatment
Kantenbehandlung
-
+
Output FPS
Ausgabe-FPS
@@ -158,7 +158,7 @@
-
+
Horizontal stretch
Horizontale Streckung
@@ -178,206 +178,221 @@
Maximale Größe
-
+
Processing settings
Verarbeitungseinstellungen
-
+
Retry Rebuild
Neuaufbau wiederholen
-
+
Edited cut recovery
Wiederherstellung bearbeiteter Schnitte
-
+
Edited cut frames could not be validated. Retry the rebuild scan.
Bearbeitete Schnittbilder konnten nicht validiert werden. Wiederholen Sie die Neuaufbauprüfung.
-
-
+
+
Rebuild from edited cuts
Aus bearbeiteten Schnitten neu aufbauen
-
-
+
+
Manage Models…
Modelle verwalten…
-
-
+
+
Manage Workspaces…
Arbeitsbereiche verwalten…
-
+
+ Reset to defaults
+ Auf Standardwerte zurücksetzen
+
+
+
+ Reset inspector parameters
+ Inspector-Parameter zurücksetzen
+
+
+
+ Compute acceleration, output directory, and output filename are not affected.
+ Rechenbeschleunigung, Ausgabeordner und Ausgabedateiname bleiben unverändert.
+
+
+
Segmentation model
Segmentierungsmodell
-
+
cached locally
lokal zwischengespeichert
-
+
not cached yet
noch nicht zwischengespeichert
-
+
Model status
Modellstatus
-
+
Model download
Modelldownload
-
+
Standard
Standard
-
+
Decontaminate colors
Farben bereinigen
-
+
fps
FPS
-
+
High output FPS may increase render cost
Hohe Ausgabe-FPS können den Renderaufwand erhöhen
-
+
Output FPS cost warning
Warnung zum Aufwand der Ausgabe-FPS
-
+
Global trim
Globaler Randbeschnitt
-
+
Global alpha trim
Globaler Alpha-Beschnitt
-
+
Padding pixels
Randpixel
-
+
Output directory
Ausgabeordner
-
+
Choose…
Auswählen…
-
+
Choose output directory
Ausgabeordner auswählen
-
+
Clear
Zurücksetzen
-
+
Clear output directory
Ausgabeordner zurücksetzen
-
+
Output filename
Ausgabedateiname
-
-
+
+
Use one non-empty filename ending in .webp; path separators are not allowed.
Verwenden Sie einen einzelnen, nicht leeren Dateinamen mit der Endung .webp; Pfadtrenner sind nicht erlaubt.
-
+
Maximum file size
Maximale Dateigröße
-
+
Unlimited
Unbegrenzt
-
+
MiB
MiB
-
+
Unlimited means no maximum file size.
Unbegrenzt bedeutet: Es gibt keine maximale Dateigröße.
-
+
%s — %s download required
%s — %s Download erforderlich
-
+
Filename must be a single non-empty .webp filename.
Der Dateiname muss ein einzelner, nicht leerer .webp-Dateiname sein.
-
+
s
s
-
+
Crop
Zuschnitt
-
+
Crop overlay
Zuschnitt-Overlay
-
+
Reset Crop
Zuschnitt zurücksetzen
-
+
Reset crop
Zuschnitt zurücksetzen
-
+
Crop %s
Zuschnitt %s
-
+
Model status: %s
Modellstatus: %s
@@ -1927,27 +1942,27 @@ Freed %s.
SourceDropSurface
-
+
Video drop area
Video-Ablagebereich
-
+
Drop a video here
Legen Sie hier ein Video ab
-
+
Open a video
Video öffnen
-
+
Open Video…
Video öffnen…
-
+
Open Video
Video öffnen
@@ -2057,17 +2072,17 @@ Freed %s.
SourceStrip
-
+
Source video
Quellvideo
-
+
Open Video…
Video öffnen…
-
+
Open Video
Video öffnen
diff --git a/resources/matteloop_en.qm b/resources/matteloop_en.qm
index c0b3841..7cd26e3 100644
Binary files a/resources/matteloop_en.qm and b/resources/matteloop_en.qm differ
diff --git a/resources/matteloop_en.ts b/resources/matteloop_en.ts
index d5ad699..e8c3ef2 100644
--- a/resources/matteloop_en.ts
+++ b/resources/matteloop_en.ts
@@ -118,13 +118,13 @@
-
+
Edge treatment
Edge treatment
-
+
Output FPS
Output FPS
@@ -158,7 +158,7 @@
-
+
Horizontal stretch
Horizontal stretch
@@ -178,206 +178,221 @@
Maximum size
-
+
Processing settings
Processing settings
-
+
Retry Rebuild
Retry Rebuild
-
+
Edited cut recovery
Edited cut recovery
-
+
Edited cut frames could not be validated. Retry the rebuild scan.
Edited cut frames could not be validated. Retry the rebuild scan.
-
-
+
+
Rebuild from edited cuts
Rebuild from edited cuts
-
-
+
+
Manage Models…
Manage Models…
-
-
+
+
Manage Workspaces…
Manage Workspaces…
-
+
+ Reset to defaults
+ Reset to defaults
+
+
+
+ Reset inspector parameters
+ Reset inspector parameters
+
+
+
+ Compute acceleration, output directory, and output filename are not affected.
+ Compute acceleration, output directory, and output filename are not affected.
+
+
+
Segmentation model
Segmentation model
-
+
cached locally
cached locally
-
+
not cached yet
not cached yet
-
+
Model status
Model status
-
+
Model download
Model download
-
+
Standard
Standard
-
+
Decontaminate colors
Decontaminate colors
-
+
fps
fps
-
+
High output FPS may increase render cost
High output FPS may increase render cost
-
+
Output FPS cost warning
Output FPS cost warning
-
+
Global trim
Global trim
-
+
Global alpha trim
Global alpha trim
-
+
Padding pixels
Padding pixels
-
+
Output directory
Output directory
-
+
Choose…
Choose…
-
+
Choose output directory
Choose output directory
-
+
Clear
Clear
-
+
Clear output directory
Clear output directory
-
+
Output filename
Output filename
-
-
+
+
Use one non-empty filename ending in .webp; path separators are not allowed.
Use one non-empty filename ending in .webp; path separators are not allowed.
-
+
Maximum file size
Maximum file size
-
+
Unlimited
Unlimited
-
+
MiB
MiB
-
+
Unlimited means no maximum file size.
Unlimited means no maximum file size.
-
+
%s — %s download required
%s — %s download required
-
+
Filename must be a single non-empty .webp filename.
Filename must be a single non-empty .webp filename.
-
+
s
s
-
+
Crop
Crop
-
+
Crop overlay
Crop overlay
-
+
Reset Crop
Reset Crop
-
+
Reset crop
Reset crop
-
+
Crop %s
Crop %s
-
+
Model status: %s
Model status: %s
@@ -1927,27 +1942,27 @@ Freed %s.
SourceDropSurface
-
+
Video drop area
Video drop area
-
+
Drop a video here
Drop a video here
-
+
Open a video
Open a video
-
+
Open Video…
Open Video…
-
+
Open Video
Open Video
@@ -2057,17 +2072,17 @@ Freed %s.
SourceStrip
-
+
Source video
Source video
-
+
Open Video…
Open Video…
-
+
Open Video
Open Video
diff --git a/src/matteloop/core/parameters.py b/src/matteloop/core/parameters.py
index e70265c..a9a1e12 100644
--- a/src/matteloop/core/parameters.py
+++ b/src/matteloop/core/parameters.py
@@ -144,6 +144,11 @@ class OutputMaxSizeChanged:
value: Decimal
+@dataclass(frozen=True, slots=True)
+class ParametersReset:
+ pass
+
+
@dataclass(frozen=True, slots=True)
class TransformChanged:
transform: TransformSpec
@@ -161,6 +166,7 @@ class TransformChanged:
| OutputDirectoryChanged
| OutputFilenameChanged
| OutputMaxSizeChanged
+ | ParametersReset
| TransformChanged
)
@@ -174,6 +180,8 @@ def reduce_parameters(state: AppState, event: ParameterEvent) -> AppState:
return state
elif not capabilities(state).can_edit:
return state
+ if isinstance(event, ParametersReset):
+ return _reduce_parameters_reset(state)
if isinstance(event, ModelChanged):
return _reduce_model(state, event)
if isinstance(event, EdgeModeChanged):
@@ -201,6 +209,39 @@ def reduce_parameters(state: AppState, event: ParameterEvent) -> AppState:
return state
+def _reduce_parameters_reset(state: AppState) -> AppState:
+ from matteloop.core.tokens import PreviewInvalidationReason
+
+ defaults = ParameterState()
+ parameters = replace(
+ state.parameters,
+ model_id=defaults.model_id,
+ edge_mode=defaults.edge_mode,
+ fps=defaults.fps,
+ trim=defaults.trim,
+ alpha_threshold=defaults.alpha_threshold,
+ padding=defaults.padding,
+ stretch_x=defaults.stretch_x,
+ max_mib=defaults.max_mib,
+ )
+ timeline = state.timeline
+ if timeline is not None and timeline.fps != defaults.fps:
+ try:
+ timeline = timeline.set_fps(defaults.fps)
+ except ValueError:
+ return state
+ if parameters == state.parameters and timeline == state.timeline:
+ return state
+ model_available = state.model_available
+ if parameters.model_id != state.parameters.model_id:
+ model_available = False
+ return _invalidate(
+ replace(state, timeline=timeline, model_available=model_available),
+ parameters,
+ PreviewInvalidationReason.CROP_CLEANUP,
+ )
+
+
def _reduce_model(state: AppState, event: ModelChanged) -> AppState:
from matteloop.core.state import PreviewInvalidated, reduce
from matteloop.core.tokens import PreviewInvalidationReason
diff --git a/src/matteloop/ui/inspector.py b/src/matteloop/ui/inspector.py
index 8ed6e08..f8425f6 100644
--- a/src/matteloop/ui/inspector.py
+++ b/src/matteloop/ui/inspector.py
@@ -65,6 +65,7 @@
)
from matteloop.ui.crop_presentation import CropPresentation
from matteloop.ui.inspector_disclosure import configure_disclosure, read_bool
+from matteloop.ui.inspector_reset import build_reset_button
from matteloop.ui.parameter_presentation import (
ParameterPresentation,
decimal_from_widget_value,
@@ -170,6 +171,7 @@ def _build_parameter_controls(self) -> None:
self._build_sampling_parameter_controls()
self._build_cleanup_parameter_controls()
self._build_output_parameter_controls()
+ self.reset_parameters_button = build_reset_button(self.command_requested.emit)
self._connect_parameter_controls()
def _build_segmentation_parameter_controls(self) -> None:
@@ -506,6 +508,7 @@ def apply_parameters(
self.clear_output_directory_button,
self.output_filename_edit,
self.max_size_spinbox,
+ self.reset_parameters_button,
):
widget.setEnabled(available)
self.fps_warning.setVisible(available and presentation.fps > 60)
@@ -764,6 +767,7 @@ def _cleanup_controls(self) -> QWidget:
layout.addRow(self._form_label("Alpha threshold"), self.alpha_threshold_spinbox)
layout.addRow(self._form_label("Padding"), self.padding_spinbox)
layout.addRow(self._form_label("Horizontal stretch"), self.stretch_spinbox)
+ layout.addRow(self._form_label(""), self.reset_parameters_button)
return controls
def _output_controls(self) -> QWidget:
@@ -825,37 +829,33 @@ def parameter_tab_widgets(self) -> tuple[QWidget, ...]:
self.clear_output_directory_button,
self.output_filename_edit,
self.max_size_spinbox,
+ self.reset_parameters_button,
)
def tab_widgets(self) -> tuple[QWidget, ...]:
"""Return the full inspector tab route in consequence order."""
return (
self.disclosures["segmentation"][0],
- self.model_picker,
- self.edge_picker,
+ self.model_picker, self.edge_picker,
self.manage_models,
self.disclosures["time_sampling"][0],
- self.fps_spinbox,
- self.start_spinbox,
- self.end_spinbox,
+ self.fps_spinbox, self.start_spinbox, self.end_spinbox,
self.duration_spinbox,
self.disclosures["crop_cleanup"][0],
*self.crop_tab_widgets(),
- self.trim_checkbox,
- self.alpha_threshold_spinbox,
- self.padding_spinbox,
+ self.trim_checkbox, self.alpha_threshold_spinbox, self.padding_spinbox,
self.stretch_spinbox,
self.disclosures["transform"][0],
*self.transform_group.tab_widgets(),
self.disclosures["output"][0],
- self.output_directory_button,
- self.clear_output_directory_button,
+ self.output_directory_button, self.clear_output_directory_button,
self.output_filename_edit,
self.max_size_spinbox,
self.disclosures["workspace"][0],
self.edited_cut_recovery,
self.rebuild_button,
self.manage_workspaces,
+ self.reset_parameters_button,
)
def crop_tab_widgets(self) -> tuple[QWidget, ...]:
diff --git a/src/matteloop/ui/inspector_reset.py b/src/matteloop/ui/inspector_reset.py
new file mode 100644
index 0000000..9aefd43
--- /dev/null
+++ b/src/matteloop/ui/inspector_reset.py
@@ -0,0 +1,30 @@
+"""Inspector action for restoring creative parameter defaults."""
+
+from __future__ import annotations
+
+from collections.abc import Callable
+
+from PySide6.QtCore import QCoreApplication
+from PySide6.QtWidgets import QPushButton
+
+from matteloop.core.parameters import ParametersReset
+
+
+def build_reset_button(emit: Callable[[object], None]) -> QPushButton:
+ """Build the reset action with an honest description of its scope."""
+ button = QPushButton(
+ QCoreApplication.translate("Inspector", "Reset to defaults")
+ )
+ button.setObjectName("reset_parameters")
+ button.setAccessibleName(
+ QCoreApplication.translate("Inspector", "Reset inspector parameters")
+ )
+ scope = QCoreApplication.translate(
+ "Inspector",
+ "Compute acceleration, output directory, and output filename are not "
+ "affected.",
+ )
+ button.setToolTip(scope)
+ button.setAccessibleDescription(scope)
+ button.clicked.connect(lambda: emit(ParametersReset()))
+ return button
diff --git a/tests/core/test_parameters.py b/tests/core/test_parameters.py
index 522789b..30642b9 100644
--- a/tests/core/test_parameters.py
+++ b/tests/core/test_parameters.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from dataclasses import dataclass
+from dataclasses import dataclass, replace
from decimal import Decimal
from fractions import Fraction
from pathlib import Path
@@ -19,12 +19,13 @@
OutputFpsChanged,
OutputMaxSizeChanged,
PaddingChanged,
+ ParametersReset,
ParameterState,
StretchChanged,
TransformChanged,
parameters_from_values,
)
-from matteloop.core.specs import EdgeMode, TransformSpec
+from matteloop.core.specs import CropSpec, EdgeMode, TransformSpec
from matteloop.core.state import (
AppState,
PreviewInvalidationReason,
@@ -163,6 +164,75 @@ def test_output_fps_changes_sampling_and_stales_the_current_preview() -> None:
assert changed.stale_category is PreviewInvalidationReason.SAMPLING
+def test_reset_restores_inspector_parameters_and_preserves_other_state() -> None:
+ current = _current()
+ assert current.timeline is not None
+ parameters = ParameterState(
+ model_id="u2net",
+ edge_mode=EdgeMode.DECONTAMINATE_COLORS,
+ execution_provider="CUDAExecutionProvider",
+ fps=90,
+ trim=True,
+ alpha_threshold=Decimal("0.4"),
+ padding=1,
+ stretch_x=Decimal("1.2"),
+ output_directory=Path("exports"),
+ output_filename="chosen.webp",
+ max_mib=Decimal("12.5"),
+ transform=TransformSpec(first_frame=1, crop=CropSpec(4, 5, 80, 70)),
+ )
+ timeline = replace(
+ current.timeline,
+ start=Fraction(1, 2),
+ end=Fraction(7, 2),
+ playhead=Fraction(1),
+ fps=90,
+ )
+ state = replace(
+ current,
+ parameters=parameters,
+ timeline=timeline,
+ crop=CropSpec(8, 9, 100, 90),
+ crop_enabled=False,
+ )
+
+ reset = reduce(state, ParametersReset())
+ defaults = ParameterState()
+
+ for name in (
+ "model_id",
+ "edge_mode",
+ "fps",
+ "trim",
+ "alpha_threshold",
+ "padding",
+ "stretch_x",
+ "max_mib",
+ ):
+ assert getattr(reset.parameters, name) == getattr(defaults, name)
+ assert reset.parameters.execution_provider == "CUDAExecutionProvider"
+ assert reset.parameters.output_directory == Path("exports")
+ assert reset.parameters.output_filename == "chosen.webp"
+ assert reset.parameters.transform == parameters.transform
+ assert reset.source_id == state.source_id
+ assert reset.source_value is state.source_value
+ assert reset.crop == state.crop
+ assert reset.crop_enabled is state.crop_enabled
+ assert reset.timeline is not None
+ assert reset.timeline.start == state.timeline.start
+ assert reset.timeline.end == state.timeline.end
+ assert reset.timeline.playhead == state.timeline.playhead
+ assert reset.timeline.fps == defaults.fps
+ assert reset.preview is PreviewState.STALE
+ assert reset.stale_category is PreviewInvalidationReason.CROP_CLEANUP
+
+
+def test_reset_parameters_is_ignored_while_a_job_runs() -> None:
+ running = reduce(_ready(), RenderRequested("job", "request"))
+
+ assert reduce(running, ParametersReset()) is running
+
+
def test_output_parameter_changes_keep_a_current_preview_current() -> None:
state = _current()
diff --git a/tests/ui/test_parameter_inspector.py b/tests/ui/test_parameter_inspector.py
index db97d70..fcfe090 100644
--- a/tests/ui/test_parameter_inspector.py
+++ b/tests/ui/test_parameter_inspector.py
@@ -8,8 +8,9 @@
from PySide6.QtCore import QSettings, Qt
from PySide6.QtWidgets import QAbstractSpinBox, QComboBox
-from matteloop.core.parameters import ParameterState
-from matteloop.core.state import AppState
+from matteloop.core.parameters import ParametersReset, ParameterState
+from matteloop.core.specs import CropSpec, EdgeMode, TransformSpec
+from matteloop.core.state import AppState, SourceState
from matteloop.core.timeline import TimelineState
from matteloop.ui.aligned_rows import (
ACCESSIBLE_DESCRIPTION_ROLE,
@@ -17,8 +18,10 @@
STATUS_ROLE,
RowStatus,
)
+from matteloop.ui.controller import SourceController
from matteloop.ui.inspector import Inspector
from matteloop.ui.parameter_presentation import present_parameters
+from matteloop.ui.store import ReducerStore
def _settings() -> QSettings:
@@ -268,6 +271,94 @@ def test_inspector_emits_edge_mode_from_the_standard_combo(qtbot) -> None:
assert [type(command).__name__ for command in commands] == ["EdgeModeChanged"]
+def test_inspector_exposes_reset_action_and_explains_what_it_preserves(qtbot) -> None:
+ inspector = Inspector(_settings())
+ qtbot.addWidget(inspector)
+ commands: list[object] = []
+ inspector.command_requested.connect(commands.append)
+
+ assert inspector.reset_parameters_button.text() == "Reset to defaults"
+ assert inspector.reset_parameters_button.accessibleName() == (
+ "Reset inspector parameters"
+ )
+ assert inspector.reset_parameters_button.toolTip() == (
+ "Compute acceleration, output directory, and output filename are not affected."
+ )
+
+ inspector.reset_parameters_button.click()
+
+ assert commands == [ParametersReset()]
+
+
+def test_inspector_reset_updates_widgets_without_disturbing_other_editors(
+ qtbot,
+) -> None:
+ settings = _settings()
+ parameters = ParameterState(
+ model_id="u2net",
+ edge_mode=EdgeMode.DECONTAMINATE_COLORS,
+ execution_provider="CUDAExecutionProvider",
+ fps=90,
+ trim=True,
+ alpha_threshold=Decimal("0.4"),
+ padding=1,
+ stretch_x=Decimal("1.2"),
+ output_directory=Path("exports"),
+ output_filename="chosen.webp",
+ max_mib=Decimal("12.5"),
+ transform=TransformSpec(first_frame=1, crop=CropSpec(4, 5, 80, 70)),
+ )
+ timeline = TimelineState(
+ Fraction(4), Fraction(1, 2), Fraction(7, 2), Fraction(1), fps=90
+ )
+ state = AppState(
+ source=SourceState.READY,
+ source_id="source",
+ source_value=object(),
+ timeline=timeline,
+ parameters=parameters,
+ crop=CropSpec(8, 9, 100, 90),
+ crop_enabled=False,
+ )
+ store = ReducerStore(state)
+ controller = SourceController.__new__(SourceController)
+ controller._store = store
+ controller._settings = settings
+ controller._working_provider = parameters.execution_provider
+ controller._failed_provider = None
+ controller._closed = False
+ inspector = Inspector(settings)
+ qtbot.addWidget(inspector)
+
+ def render(updated: AppState) -> None:
+ inspector.apply_parameters(present_parameters(updated), editable=True)
+
+ store.subscribe(render)
+ inspector.command_requested.connect(controller.dispatch)
+ inspector.apply_parameters(present_parameters(state), editable=True)
+ inspector.reset_parameters_button.click()
+
+ defaults = ParameterState()
+ assert inspector.model_picker.currentData() == defaults.model_id
+ assert inspector.edge_picker.currentData() == defaults.edge_mode.value
+ assert inspector.fps_spinbox.value() == defaults.fps
+ assert inspector.trim_checkbox.isChecked() is defaults.trim
+ assert inspector.alpha_threshold_spinbox.value() == float(defaults.alpha_threshold)
+ assert inspector.padding_spinbox.value() == defaults.padding
+ assert inspector.stretch_spinbox.value() == float(defaults.stretch_x)
+ assert inspector.max_size_spinbox.value() == float(defaults.max_mib)
+ assert store.state.parameters.execution_provider == parameters.execution_provider
+ assert store.state.parameters.output_directory == parameters.output_directory
+ assert store.state.parameters.output_filename == parameters.output_filename
+ assert store.state.parameters.transform == parameters.transform
+ assert store.state.crop == state.crop
+ assert store.state.crop_enabled is state.crop_enabled
+ assert store.state.timeline is not None
+ assert store.state.timeline.start == timeline.start
+ assert store.state.timeline.end == timeline.end
+ assert store.state.timeline.playhead == timeline.playhead
+
+
def test_inspector_exposes_and_emits_output_directory_clear(qtbot) -> None:
inspector = Inspector(_settings())
qtbot.addWidget(inspector)
diff --git a/tests/ui/test_parameter_persistence.py b/tests/ui/test_parameter_persistence.py
index d31c336..ab173ee 100644
--- a/tests/ui/test_parameter_persistence.py
+++ b/tests/ui/test_parameter_persistence.py
@@ -10,7 +10,11 @@
CUDA_EXECUTION_PROVIDER,
ProviderOption,
)
-from matteloop.core.parameters import OutputFilenameChanged, ParameterState
+from matteloop.core.parameters import (
+ OutputFilenameChanged,
+ ParametersReset,
+ ParameterState,
+)
from matteloop.core.specs import CropSpec, EdgeMode, TransformSpec
from matteloop.core.state import AppState, SourceState
from matteloop.ui.controller import SourceController
@@ -103,3 +107,54 @@ def test_failed_provider_is_not_reintroduced_by_a_later_parameter_save() -> None
controller._dispatch_parameter(OutputFilenameChanged("next.webp"))
assert settings.value("parameters/execution_provider") == CPU_EXECUTION_PROVIDER
+
+
+def test_reset_persists_inspector_defaults_without_overwriting_excluded_choices(
+) -> None:
+ settings = _settings()
+ saved = ParameterState(
+ model_id="u2net",
+ edge_mode=EdgeMode.DECONTAMINATE_COLORS,
+ execution_provider=CUDA_EXECUTION_PROVIDER,
+ fps=90,
+ trim=True,
+ alpha_threshold=Decimal("0.4"),
+ padding=1,
+ stretch_x=Decimal("1.2"),
+ output_directory=Path("exports"),
+ output_filename="chosen.webp",
+ max_mib=Decimal("12.5"),
+ )
+ persist_parameters(settings, saved)
+ store = ReducerStore(
+ AppState(
+ source=SourceState.READY,
+ source_id="source",
+ source_value=object(),
+ parameters=saved,
+ )
+ )
+ controller = SourceController.__new__(SourceController)
+ controller._store = store
+ controller._settings = settings
+ controller._working_provider = CUDA_EXECUTION_PROVIDER
+ controller._failed_provider = None
+
+ controller._dispatch_parameter(ParametersReset())
+ actual = load_parameters(settings)
+ defaults = ParameterState()
+
+ for name in (
+ "model_id",
+ "edge_mode",
+ "fps",
+ "trim",
+ "alpha_threshold",
+ "padding",
+ "stretch_x",
+ "max_mib",
+ ):
+ assert getattr(actual, name) == getattr(defaults, name)
+ assert actual.execution_provider == saved.execution_provider
+ assert actual.output_directory == saved.output_directory
+ assert actual.output_filename == saved.output_filename