1515
1616from __future__ import annotations
1717
18+ import logging
1819import os
1920from dataclasses import dataclass
2021from pathlib import PurePath , PurePosixPath
6364 from mypy_boto3_s3 import S3Client
6465 from ome_zarr .reader import Node # type: ignore[import-untyped]
6566
67+ logger = logging .getLogger (__name__ )
68+
6669T = TypeVar ("T" , int , float )
70+ _KNOWN_GOOD_PIPELINE_VERSIONS = {3 , 4 , 5 }
6771
6872
6973@dataclass (slots = True , frozen = True )
@@ -227,7 +231,7 @@ def _zarr_base_name_any(base: str) -> str | None:
227231 )
228232}
229233
230- _PIPELINE_INDIVIDUAL_TRANSFORM_CHAINS : dict [int , TransformChain ] = {
234+ _KNOWN_INDIVIDUAL_TRANSFORM_CHAINS : dict [int , TransformChain ] = {
231235 3 : TransformChain (
232236 fixed = "template" ,
233237 moving = "individual" ,
@@ -244,6 +248,34 @@ def _zarr_base_name_any(base: str) -> str | None:
244248 )
245249}
246250
251+ _PIPELINE_INDIVIDUAL_TRANSFORM_CHAINS : dict [int , TransformChain ] = {
252+ 3 : _KNOWN_INDIVIDUAL_TRANSFORM_CHAINS [3 ],
253+ 4 : _KNOWN_INDIVIDUAL_TRANSFORM_CHAINS [3 ],
254+ 5 : _KNOWN_INDIVIDUAL_TRANSFORM_CHAINS [3 ],
255+ }
256+
257+
258+ def _resolve_individual_transform_chain (
259+ pipeline_ver : int ,
260+ ) -> TransformChain :
261+ """Look up the individual (LS → template) transform chain for a pipeline major version.
262+
263+ Falls back to the latest known chain when the version is newer than
264+ anything registered.
265+ """
266+ chain = _PIPELINE_INDIVIDUAL_TRANSFORM_CHAINS .get (pipeline_ver )
267+ if chain is not None :
268+ return chain
269+ max_known = max (_PIPELINE_INDIVIDUAL_TRANSFORM_CHAINS )
270+ if pipeline_ver > max_known :
271+ logger .warning (
272+ f"No individual transform chain registered for pipeline "
273+ f"version { pipeline_ver } ; falling back to chain for version "
274+ f"{ max_known } . Results may not be accurate."
275+ )
276+ return _PIPELINE_INDIVIDUAL_TRANSFORM_CHAINS [max_known ]
277+ raise ValueError (f"No individual transform chain registered for pipeline version { pipeline_ver } " )
278+
247279
248280def _get_processing_pipeline_data (
249281 processing_data : dict [str , Any ],
@@ -265,14 +297,25 @@ def _get_processing_pipeline_data(
265297 Raises
266298 ------
267299 ValueError
268- If the pipeline version is missing or the major version is not 3.
300+ If the pipeline version is missing or the major version is older
301+ than the minimum supported version. Newer-than-known versions emit
302+ a warning instead of raising.
269303 """
270304 ver_str = processing_data .get ("processing_pipeline" , {}).get ("pipeline_version" , None )
271305 if not ver_str :
272306 raise ValueError ("Missing pipeline version" )
273307 pipeline_ver = int (ver_str .split ("." )[0 ])
274- if pipeline_ver not in set ((3 , 4 )):
275- raise ValueError (f"Unsupported pipeline version: { pipeline_ver } " )
308+ if pipeline_ver not in _KNOWN_GOOD_PIPELINE_VERSIONS :
309+ maxver = max (_KNOWN_GOOD_PIPELINE_VERSIONS )
310+ if pipeline_ver > maxver :
311+ logger .warning (
312+ f"Pipeline version { pipeline_ver } is greater than max "
313+ f"verified version { maxver } , results may not be accurate. "
314+ "File an issue at "
315+ "https://github.com/AllenNeuralDynamics/aind-zarr-utils/issues."
316+ )
317+ else :
318+ raise ValueError (f"Unsupported pipeline version: { pipeline_ver } " )
276319 pipeline : dict [str , Any ] = processing_data .get ("processing_pipeline" , {})
277320 return pipeline
278321
@@ -1175,9 +1218,13 @@ def pipeline_transforms(
11751218 bucket ,
11761219 asset_pathlike / alignment_rel_path ,
11771220 )
1221+ pipeline = _get_processing_pipeline_data (processing_data )
1222+ pipeline_ver = int (pipeline ["pipeline_version" ].split ("." )[0 ])
1223+ transform_chain = _resolve_individual_transform_chain (pipeline_ver )
1224+
11781225 individual_ants_paths = TemplatePaths (
11791226 alignment_path ,
1180- _PIPELINE_INDIVIDUAL_TRANSFORM_CHAINS [ 3 ] ,
1227+ transform_chain ,
11811228 )
11821229 if template_base :
11831230 template_ants_paths = TemplatePaths (
0 commit comments