photo-stack-finder 0.1.7__py3-none-any.whl → 0.1.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. orchestrator/__init__.py +2 -2
  2. orchestrator/app.py +6 -11
  3. orchestrator/build_pipeline.py +19 -21
  4. orchestrator/orchestrator_runner.py +11 -8
  5. orchestrator/pipeline_builder.py +126 -126
  6. orchestrator/pipeline_orchestrator.py +604 -604
  7. orchestrator/review_persistence.py +162 -162
  8. orchestrator/static/orchestrator.css +76 -76
  9. orchestrator/static/orchestrator.html +11 -5
  10. orchestrator/static/orchestrator.js +3 -1
  11. overlap_metrics/__init__.py +1 -1
  12. overlap_metrics/config.py +135 -135
  13. overlap_metrics/core.py +284 -284
  14. overlap_metrics/estimators.py +292 -292
  15. overlap_metrics/metrics.py +307 -307
  16. overlap_metrics/registry.py +99 -99
  17. overlap_metrics/utils.py +104 -104
  18. photo_compare/__init__.py +1 -1
  19. photo_compare/base.py +285 -285
  20. photo_compare/config.py +225 -225
  21. photo_compare/distance.py +15 -15
  22. photo_compare/feature_methods.py +173 -173
  23. photo_compare/file_hash.py +29 -29
  24. photo_compare/hash_methods.py +99 -99
  25. photo_compare/histogram_methods.py +118 -118
  26. photo_compare/pixel_methods.py +58 -58
  27. photo_compare/structural_methods.py +104 -104
  28. photo_compare/types.py +28 -28
  29. {photo_stack_finder-0.1.7.dist-info → photo_stack_finder-0.1.8.dist-info}/METADATA +21 -22
  30. photo_stack_finder-0.1.8.dist-info/RECORD +75 -0
  31. scripts/orchestrate.py +12 -10
  32. utils/__init__.py +4 -3
  33. utils/base_pipeline_stage.py +171 -171
  34. utils/base_ports.py +176 -176
  35. utils/benchmark_utils.py +823 -823
  36. utils/channel.py +74 -74
  37. utils/comparison_gates.py +40 -21
  38. utils/compute_benchmarks.py +355 -355
  39. utils/compute_identical.py +94 -24
  40. utils/compute_indices.py +235 -235
  41. utils/compute_perceptual_hash.py +127 -127
  42. utils/compute_perceptual_match.py +240 -240
  43. utils/compute_sha_bins.py +64 -20
  44. utils/compute_template_similarity.py +1 -1
  45. utils/compute_versions.py +483 -483
  46. utils/config.py +8 -5
  47. utils/data_io.py +83 -83
  48. utils/graph_context.py +44 -44
  49. utils/logger.py +2 -2
  50. utils/models.py +2 -2
  51. utils/photo_file.py +90 -91
  52. utils/pipeline_graph.py +334 -334
  53. utils/pipeline_stage.py +408 -408
  54. utils/plot_helpers.py +123 -123
  55. utils/ports.py +136 -136
  56. utils/progress.py +415 -415
  57. utils/report_builder.py +139 -139
  58. utils/review_types.py +55 -55
  59. utils/review_utils.py +10 -19
  60. utils/sequence.py +10 -8
  61. utils/sequence_clustering.py +1 -1
  62. utils/template.py +57 -57
  63. utils/template_parsing.py +71 -0
  64. photo_stack_finder-0.1.7.dist-info/RECORD +0 -74
  65. {photo_stack_finder-0.1.7.dist-info → photo_stack_finder-0.1.8.dist-info}/WHEEL +0 -0
  66. {photo_stack_finder-0.1.7.dist-info → photo_stack_finder-0.1.8.dist-info}/entry_points.txt +0 -0
  67. {photo_stack_finder-0.1.7.dist-info → photo_stack_finder-0.1.8.dist-info}/licenses/LICENSE +0 -0
  68. {photo_stack_finder-0.1.7.dist-info → photo_stack_finder-0.1.8.dist-info}/top_level.txt +0 -0
utils/base_ports.py CHANGED
@@ -1,176 +1,176 @@
1
- """Base classes for port-based pipeline connectivity.
2
-
3
- This module contains the non-generic base classes that define the port interface.
4
- These classes have minimal dependencies to avoid circular imports.
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from abc import ABC, abstractmethod
10
- from typing import Protocol
11
-
12
-
13
- class StageProtocol(Protocol):
14
- """Protocol defining the minimal interface needed from a pipeline stage.
15
-
16
- This avoids circular dependency with pipeline_stage module.
17
- """
18
-
19
- stage_name: str
20
-
21
- def get_cache_timestamp(self) -> float:
22
- """Get timestamp when outputs were last computed.
23
-
24
- Returns:
25
- Modification time in seconds since epoch
26
- """
27
- ...
28
-
29
- def get_ref_photo_count(self) -> int | None:
30
- """Get count of reference photos after stage has run.
31
-
32
- Returns:
33
- Count of reference photos, or None if not available or stage hasn't run
34
- """
35
- ...
36
-
37
- def get_ref_sequence_count(self) -> int | None:
38
- """Get count of reference sequences after stage has run.
39
-
40
- Returns:
41
- Count of reference sequences, or None if not available or stage hasn't run
42
- """
43
- ...
44
-
45
-
46
- class BaseOutputPort:
47
- """Non-generic base class for output ports.
48
-
49
- Enables type checking and collections that work with any output port
50
- regardless of data type. Useful for graph validation where we check
51
- port connectivity without reading data.
52
- """
53
-
54
- owner: StageProtocol # Actual type is PipelineStage, but avoiding circular import
55
-
56
- def __init__(
57
- self,
58
- owner: StageProtocol,
59
- ):
60
- """Initialize output port.
61
-
62
- Args:
63
- owner: The stage that produces this output (used for timestamps)
64
-
65
- """
66
- self.owner = owner
67
-
68
- def timestamp(self) -> float:
69
- """Get when this output was last updated.
70
-
71
- All output ports from the same stage share the same timestamp
72
- (they are computed together).
73
-
74
- Returns:
75
- Modification time in seconds since epoch, or 0.0 if never computed
76
- """
77
- return self.owner.get_cache_timestamp()
78
-
79
- def get_ref_photo_count(self) -> int | None:
80
- """Get count of reference photos from owner stage.
81
-
82
- Returns:
83
- Count of reference photos in the owner, or None if not available
84
- """
85
- return self.owner.get_ref_photo_count()
86
-
87
- def get_ref_sequence_count(self) -> int | None:
88
- """Get count of reference sequences from owner stage.
89
-
90
- Returns:
91
- Count of reference sequences in the owner, or None if not available
92
- """
93
- return self.owner.get_ref_sequence_count()
94
-
95
-
96
- class BaseInputPort(ABC):
97
- """Non-generic base class for input ports.
98
-
99
- Enables type checking and collections that work with any input port
100
- regardless of data type. Useful for graph validation where we check
101
- port connectivity without reading data.
102
- """
103
-
104
- _source: BaseOutputPort | None
105
- name: str
106
-
107
- def __init__(self, name: str):
108
- """Initialize input port.
109
-
110
- Args:
111
- name: Descriptive name for this input (e.g., "sha_bins", "forest")
112
- """
113
- self.name = name
114
-
115
- @abstractmethod
116
- def is_bound(self) -> bool:
117
- """Check if this input is connected to a source.
118
-
119
- Returns:
120
- True if bind() has been called, False otherwise
121
- """
122
- ...
123
-
124
- def timestamp(self) -> float:
125
- """Get timestamp from connected output.
126
-
127
- Returns:
128
- Timestamp from bound output port, or 0.0 if not bound
129
-
130
- Raises:
131
- RuntimeError: If port is not bound (should check is_bound() first)
132
- """
133
- if self._source is None:
134
- raise RuntimeError(f"Input port '{self.name}' is not bound to any source")
135
- ts = self._source.timestamp()
136
- if ts is None:
137
- raise RuntimeError(f"{self._source.owner.stage_name} is reporting None timestamp")
138
- return ts
139
-
140
- def get_ref_photo_count(self) -> int | None:
141
- """Get count of reference photos from connected source.
142
-
143
- Returns:
144
- Count of reference photos from source, or None if not available
145
-
146
- Raises:
147
- RuntimeError: If port is not bound to a source
148
- """
149
- if self._source is None:
150
- raise RuntimeError(f"Input port '{self.name}' is not bound to any source")
151
- return self._source.get_ref_photo_count()
152
-
153
- def get_ref_sequence_count(self) -> int | None:
154
- """Get count of reference sequences from connected source.
155
-
156
- Returns:
157
- Count of reference sequences from source, or None if not available
158
-
159
- Raises:
160
- RuntimeError: If port is not bound to a source
161
- """
162
- if self._source is None:
163
- raise RuntimeError(f"Input port '{self.name}' is not bound to any source")
164
- return self._source.get_ref_sequence_count()
165
-
166
-
167
- class BaseChannel:
168
- """Non-generic base class for channels.
169
-
170
- Enables type checking and collections that work with any channel
171
- regardless of data type. Useful for graph storage where we track
172
- channels with different type parameters.
173
- """
174
-
175
- output: BaseOutputPort
176
- input: BaseInputPort
1
+ """Base classes for port-based pipeline connectivity.
2
+
3
+ This module contains the non-generic base classes that define the port interface.
4
+ These classes have minimal dependencies to avoid circular imports.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from abc import ABC, abstractmethod
10
+ from typing import Protocol
11
+
12
+
13
+ class StageProtocol(Protocol):
14
+ """Protocol defining the minimal interface needed from a pipeline stage.
15
+
16
+ This avoids circular dependency with pipeline_stage module.
17
+ """
18
+
19
+ stage_name: str
20
+
21
+ def get_cache_timestamp(self) -> float:
22
+ """Get timestamp when outputs were last computed.
23
+
24
+ Returns:
25
+ Modification time in seconds since epoch
26
+ """
27
+ ...
28
+
29
+ def get_ref_photo_count(self) -> int | None:
30
+ """Get count of reference photos after stage has run.
31
+
32
+ Returns:
33
+ Count of reference photos, or None if not available or stage hasn't run
34
+ """
35
+ ...
36
+
37
+ def get_ref_sequence_count(self) -> int | None:
38
+ """Get count of reference sequences after stage has run.
39
+
40
+ Returns:
41
+ Count of reference sequences, or None if not available or stage hasn't run
42
+ """
43
+ ...
44
+
45
+
46
+ class BaseOutputPort:
47
+ """Non-generic base class for output ports.
48
+
49
+ Enables type checking and collections that work with any output port
50
+ regardless of data type. Useful for graph validation where we check
51
+ port connectivity without reading data.
52
+ """
53
+
54
+ owner: StageProtocol # Actual type is PipelineStage, but avoiding circular import
55
+
56
+ def __init__(
57
+ self,
58
+ owner: StageProtocol,
59
+ ):
60
+ """Initialize output port.
61
+
62
+ Args:
63
+ owner: The stage that produces this output (used for timestamps)
64
+
65
+ """
66
+ self.owner = owner
67
+
68
+ def timestamp(self) -> float:
69
+ """Get when this output was last updated.
70
+
71
+ All output ports from the same stage share the same timestamp
72
+ (they are computed together).
73
+
74
+ Returns:
75
+ Modification time in seconds since epoch, or 0.0 if never computed
76
+ """
77
+ return self.owner.get_cache_timestamp()
78
+
79
+ def get_ref_photo_count(self) -> int | None:
80
+ """Get count of reference photos from owner stage.
81
+
82
+ Returns:
83
+ Count of reference photos in the owner, or None if not available
84
+ """
85
+ return self.owner.get_ref_photo_count()
86
+
87
+ def get_ref_sequence_count(self) -> int | None:
88
+ """Get count of reference sequences from owner stage.
89
+
90
+ Returns:
91
+ Count of reference sequences in the owner, or None if not available
92
+ """
93
+ return self.owner.get_ref_sequence_count()
94
+
95
+
96
+ class BaseInputPort(ABC):
97
+ """Non-generic base class for input ports.
98
+
99
+ Enables type checking and collections that work with any input port
100
+ regardless of data type. Useful for graph validation where we check
101
+ port connectivity without reading data.
102
+ """
103
+
104
+ _source: BaseOutputPort | None
105
+ name: str
106
+
107
+ def __init__(self, name: str):
108
+ """Initialize input port.
109
+
110
+ Args:
111
+ name: Descriptive name for this input (e.g., "sha_bins", "forest")
112
+ """
113
+ self.name = name
114
+
115
+ @abstractmethod
116
+ def is_bound(self) -> bool:
117
+ """Check if this input is connected to a source.
118
+
119
+ Returns:
120
+ True if bind() has been called, False otherwise
121
+ """
122
+ ...
123
+
124
+ def timestamp(self) -> float:
125
+ """Get timestamp from connected output.
126
+
127
+ Returns:
128
+ Timestamp from bound output port, or 0.0 if not bound
129
+
130
+ Raises:
131
+ RuntimeError: If port is not bound (should check is_bound() first)
132
+ """
133
+ if self._source is None:
134
+ raise RuntimeError(f"Input port '{self.name}' is not bound to any source")
135
+ ts = self._source.timestamp()
136
+ if ts is None:
137
+ raise RuntimeError(f"{self._source.owner.stage_name} is reporting None timestamp")
138
+ return ts
139
+
140
+ def get_ref_photo_count(self) -> int | None:
141
+ """Get count of reference photos from connected source.
142
+
143
+ Returns:
144
+ Count of reference photos from source, or None if not available
145
+
146
+ Raises:
147
+ RuntimeError: If port is not bound to a source
148
+ """
149
+ if self._source is None:
150
+ raise RuntimeError(f"Input port '{self.name}' is not bound to any source")
151
+ return self._source.get_ref_photo_count()
152
+
153
+ def get_ref_sequence_count(self) -> int | None:
154
+ """Get count of reference sequences from connected source.
155
+
156
+ Returns:
157
+ Count of reference sequences from source, or None if not available
158
+
159
+ Raises:
160
+ RuntimeError: If port is not bound to a source
161
+ """
162
+ if self._source is None:
163
+ raise RuntimeError(f"Input port '{self.name}' is not bound to any source")
164
+ return self._source.get_ref_sequence_count()
165
+
166
+
167
+ class BaseChannel:
168
+ """Non-generic base class for channels.
169
+
170
+ Enables type checking and collections that work with any channel
171
+ regardless of data type. Useful for graph storage where we track
172
+ channels with different type parameters.
173
+ """
174
+
175
+ output: BaseOutputPort
176
+ input: BaseInputPort