Skip to content

Commit 00a262d

Browse files
Consolidate shared sync protocol name validation
1 parent d02459a commit 00a262d

2 files changed

Lines changed: 40 additions & 26 deletions

File tree

flepimop/gempyor_pkg/src/gempyor/batch/_cli.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
parse_config_files,
2525
verbosity_options,
2626
)
27+
from ..sync._sync import _get_sync_protocol
2728
from ..utils import _dump_formatted_yaml, _git_checkout, config
2829
from ._estimate import _estimate_job_resources, _format_resource_bounds
2930
from ._helpers import _job_name, _parse_extra_options
@@ -478,13 +479,9 @@ def _click_batch_calibrate(ctx: click.Context = mock_context, **kwargs: Any) ->
478479
# Ensure that sync protocol if given is valid
479480
cfg_sync_protocols = dict(cfg["sync"].get()) if cfg["sync"].exists() else {}
480481
if (sync_protocol := kwargs.get("sync_protocol", None)) is not None:
481-
# --sync-protocol was given, implicit --sync
482+
# --sync-protocol was given
482483
logger.info("User provided explicit sync protocol of '%s'", sync_protocol)
483-
if sync_protocol not in cfg_sync_protocols:
484-
raise ValueError(
485-
f"Sync protocol '{sync_protocol}' not found in the config file. "
486-
f"Valid protocols are: {', '.join(cfg_sync_protocols.keys())}."
487-
)
484+
_get_sync_protocol(cfg_sync_protocols, sync_protocol)
488485
logger.info(
489486
"Using sync protocol '%s' with options '%s' to sync the model outputs.",
490487
sync_protocol,

flepimop/gempyor_pkg/src/gempyor/sync/_sync.py

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
BaseModel,
1717
ConfigDict,
1818
Field,
19+
TypeAdapter,
1920
model_validator,
2021
)
2122

@@ -443,6 +444,36 @@ def _sync_pydantic(
443444

444445

445446
SyncModel = Annotated[RsyncModel | S3SyncModel | GitModel, Field(discriminator="type")]
447+
sync_model_adapter = TypeAdapter(SyncModel)
448+
449+
450+
def _get_sync_protocol(sync: dict[str, dict | SyncABC], protocol: str | None) -> SyncModel:
451+
"""
452+
Get the sync protocol model from the provided dictionary.
453+
454+
Args:
455+
sync: A dictionary of sync protocols, where the keys are protocol names and
456+
the values are `SyncModel` instances or dictionaries that can be validated
457+
into a `SyncModel`.
458+
protocol: The name of the protocol to retrieve. If `None`, the first protocol
459+
in the dictionary will be used.
460+
461+
Returns:
462+
The sync protocol model corresponding to the provided protocol name.
463+
464+
Raises:
465+
ValueError: If the specified protocol is not found in the dictionary.
466+
"""
467+
protocol_names = sync.keys()
468+
target_protocol = protocol_names[0] if protocol is None else protocol
469+
if (sync_model := sync.get(target_protocol)) is None:
470+
raise ValueError(
471+
f"Protocol '{target_protocol}' not found, available protocols are: "
472+
f"{', '.join(protocol_names)}."
473+
)
474+
if not issubclass(sync_model, SyncABC):
475+
sync_model = sync_model_adapter.validate_python(sync_model)
476+
return sync_model
446477

447478

448479
class SyncProtocols(SyncABC):
@@ -465,26 +496,12 @@ def _sync_pydantic(
465496
if not self.sync:
466497
logger.info("No protocols to sync.")
467498
return run(["echo", "No protocols to sync"], check=True)
468-
target_protocol = (
469-
sync_options.protocol if sync_options.protocol else list(self.sync.keys())[0]
470-
)
471-
logger.debug("Resolved protocol: %s.", str(target_protocol))
472-
if proto := self.sync.get(target_protocol):
473-
logger.info("Executing protocol: %s.", str(proto))
474-
return proto.execute(sync_options, verbosity)
475-
logger.error(
476-
"Protocol '%s' not found, available protocols are: %s.",
477-
target_protocol,
478-
", ".join(self.sync.keys()),
479-
)
480-
return run(
481-
[
482-
"echo",
483-
f"Protocol '{target_protocol}' not found, available "
484-
f"protocols are: {', '.join(self.sync.keys())}.",
485-
],
486-
check=True,
487-
)
499+
try:
500+
sync_model = _get_sync_protocol(self.sync, sync_options.protocol)
501+
except ValueError as e:
502+
logger.critical(str(e))
503+
return run(["echo", str(e)], check=True)
504+
return sync_model.execute(sync_options, verbosity)
488505

489506

490507
def sync_from_yaml(

0 commit comments

Comments
 (0)