@@ -152,7 +152,7 @@ def run_eval(
152152 """
153153 evaluators_worker_pool = ThreadPoolExecutor (max_workers = workers )
154154
155- hl_file , function_ = _get_hl_file (client = client , file = file )
155+ hl_file , function_ = _get_hl_file (client = client , file_config = file )
156156 type_ = hl_file .type
157157 try :
158158 hl_dataset = _upsert_dataset (dataset = dataset , client = client )
@@ -415,48 +415,52 @@ def _safe_get_default_file_version(client: "BaseHumanloop", file_config: FileEva
415415 raise HumanloopRuntimeError ("You must provide a path or id in your `file`." )
416416
417417 if path is not None :
418- try :
419- hl_file = client .files .retrieve_by_path (path = path )
420- if hl_file .type != type :
421- raise HumanloopRuntimeError (
422- f"File in Humanloop workspace at { path } is not of type { type } , but { hl_file .type } ."
423- )
424- return hl_file
425- except ApiError as e :
426- if e .status_code == 404 :
427- raise HumanloopRuntimeError (f"File with path { path } not found. Please check your path and try again." )
428- raise e
418+ hl_file = client .files .retrieve_by_path (path = path )
419+ if hl_file .type != type :
420+ raise HumanloopRuntimeError (
421+ f"File in Humanloop workspace at { path } is not of type { type } , but { hl_file .type } ."
422+ )
423+ return hl_file
429424 else :
430- subclient = _get_subclient (client , file_config )
431- try :
432- return subclient .get (id = file_id )
433- except ApiError as e :
434- if e .status_code == 404 :
435- raise HumanloopRuntimeError (f"File with id { file_id } not found. Please check your id and try again." )
436- raise e
425+ subclient = _get_subclient (client = client , file_config = file_config )
426+ return subclient .get (id = file_id )
437427
438428
439429def _resolve_file (client : "BaseHumanloop" , file_config : FileEvalConfig ) -> tuple [EvaluatedFile , Optional [Callable ]]:
440430 """Resolve the File to be evaluated. Will return a FileResponse and an optional callable.
441431
442432 If the callable is null, the File will be evaluated on Humanloop. Otherwise, the File will be evaluated locally.
443433 """
444- if file_config .get ("version" ) is not None and file_config .get ("path" ) is None :
445- raise HumanloopRuntimeError (
446- "You are trying to create a new version of the File by passing the `version` argument. You must also pass the `path` argument."
447- )
448434 hl_file = _safe_get_default_file_version (client = client , file_config = file_config )
449- if "version" in file_config :
450- # User wants to upsert a version
451- return (
452- _upsert_file (file_config = file_config , client = client ),
453- _get_file_callable (file_config ),
454- )
435+ file_id = file_config .get ("id" )
436+ path = file_config .get ("path" )
455437 version_id = file_config .get ("version_id" )
456438 environment = file_config .get ("environment" )
439+ callable = _get_file_callable (file_config = file_config )
440+ version = file_config .get ("version" )
441+
442+ if version is not None and path is None and file_id :
443+ raise HumanloopRuntimeError (
444+ "You are trying to create a new version of the File by passing the `version` argument. You must pass either the `file.path` or `file.id` argument."
445+ )
446+
447+ if version :
448+ # User wants to upsert a version
449+ return (_upsert_file (file_config = file_config , client = client ), callable )
450+
457451 if version_id is None and environment is None :
458452 # Return default version of the File
459- return hl_file , None
453+ return hl_file , callable
454+
455+ if callable :
456+ raise HumanloopRuntimeError (
457+ "You cannot request local evaluation while requesting a specific File version by version ID or environment"
458+ )
459+
460+ if file_id is None and (version_id or environment ):
461+ raise HumanloopRuntimeError (
462+ "You must provide the `file.id` when addressing a file by version ID or environment"
463+ )
460464 # Use version_id or environment to retrieve specific version of the File
461465 subclient = _get_subclient (client = client , file_config = file_config )
462466 # Let backend handle case where both or none of version_id and environment are provided
@@ -466,21 +470,21 @@ def _resolve_file(client: "BaseHumanloop", file_config: FileEvalConfig) -> tuple
466470 ), None
467471
468472
469- def _get_hl_file (client : "BaseHumanloop" , file : FileEvalConfig ) -> tuple [EvaluatedFile , Optional [Callable ]]:
473+ def _get_hl_file (client : "BaseHumanloop" , file_config : FileEvalConfig ) -> tuple [EvaluatedFile , Optional [Callable ]]:
470474 """Check if the config object is valid, and resolve the File to be evaluated
471475
472476 The callable will be null if the evaluation will happen on Humanloop runtime.
473477 Otherwise, the evaluation will happen locally.
474478 """
475- file_ = _file_or_file_inside_hl_decorator (file )
479+ file_ = _file_or_file_inside_hl_decorator (file_config )
476480 file_ = _check_file_type (file_ )
477481
478482 return _resolve_file (client = client , file_config = file_ )
479483
480484
481- def _callable_is_hl_utility (file : FileEvalConfig ) -> bool :
485+ def _callable_is_hl_utility (file_config : FileEvalConfig ) -> bool :
482486 """Check if a File is a decorated function."""
483- return hasattr (file .get ("callable" , {}), "file" )
487+ return hasattr (file_config .get ("callable" , {}), "file" )
484488
485489
486490def _wait_for_evaluation_to_complete (
@@ -557,37 +561,37 @@ def _get_checks(
557561 return checks
558562
559563
560- def _file_or_file_inside_hl_decorator (file : FileEvalConfig ) -> FileEvalConfig :
561- if _callable_is_hl_utility (file ):
562- inner_file : FileEvalConfig = file ["callable" ].file # type: ignore [misc, attr-defined]
563- function_ = file ["callable" ]
564- type_ = file ["type" ]
564+ def _file_or_file_inside_hl_decorator (file_config : FileEvalConfig ) -> FileEvalConfig :
565+ if _callable_is_hl_utility (file_config ):
566+ inner_file : FileEvalConfig = file_config ["callable" ].file # type: ignore [misc, attr-defined]
567+ function_ = file_config ["callable" ]
568+ type_ = file_config ["type" ]
565569 decorator_type = function_ .file ["type" ] # type: ignore [attr-defined, union-attr]
566570 if decorator_type != type_ :
567571 raise HumanloopRuntimeError (
568572 "The type of the decorated function does not match the type of the file. Expected `%s`, got `%s`."
569573 % (type_ .capitalize (), decorator_type .capitalize ())
570574 )
571- if "path" in file and inner_file ["path" ] != file ["path" ]:
575+ if "path" in file_config and inner_file ["path" ] != file_config ["path" ]:
572576 raise HumanloopRuntimeError (
573577 "`path` attribute specified in the `file` does not match the path of the decorated function. "
574- f"Expected `{ inner_file ['path' ]} `, got `{ file ['path' ]} `."
578+ f"Expected `{ inner_file ['path' ]} `, got `{ file_config ['path' ]} `."
575579 )
576- if "id" in file :
580+ if "id" in file_config :
577581 raise HumanloopRuntimeError (
578582 "Do not specify an `id` attribute in `file` argument when using a decorated function."
579583 )
580- if "version" in file :
584+ if "version" in file_config :
581585 if inner_file ["type" ] != "prompt" :
582586 raise HumanloopRuntimeError (
583587 f"Do not specify a `version` attribute in `file` argument when using a { inner_file ['type' ].capitalize ()} decorated function."
584588 )
585- if "type" in file and inner_file ["type" ] != file ["type" ]:
589+ if "type" in file_config and inner_file ["type" ] != file_config ["type" ]:
586590 raise HumanloopRuntimeError (
587591 "Attribute `type` of `file` argument does not match the file type of the decorated function. "
588- f"Expected `{ inner_file ['type' ]} `, got `{ file ['type' ]} `."
592+ f"Expected `{ inner_file ['type' ]} `, got `{ file_config ['type' ]} `."
589593 )
590- if "id" in file :
594+ if "id" in file_config :
591595 raise HumanloopRuntimeError (
592596 "Do not specify an `id` attribute in `file` argument when using a decorated function."
593597 )
@@ -602,9 +606,9 @@ def _file_or_file_inside_hl_decorator(file: FileEvalConfig) -> FileEvalConfig:
602606 f"{ RESET } "
603607 )
604608 # TODO: document this
605- file_ ["version" ] = file ["version" ]
609+ file_ ["version" ] = file_config ["version" ]
606610 else :
607- file_ = copy .deepcopy (file )
611+ file_ = copy .deepcopy (file_config )
608612
609613 # Raise error if neither path nor id is provided
610614 if not file_ .get ("path" ) and not file_ .get ("id" ):
@@ -807,7 +811,7 @@ def _call_function(
807811 try :
808812 output = json .dumps (output )
809813 except Exception :
810- # throw error if it fails to serialize
814+ # throw error if output fails to serialize
811815 raise ValueError (f"Your { type } 's `callable` must return a string or a JSON serializable object." )
812816 return output
813817
0 commit comments