diff --git a/skyvern/client/core/http_client.py b/skyvern/client/core/http_client.py index e4173f990f..84e1409600 100644 --- a/skyvern/client/core/http_client.py +++ b/skyvern/client/core/http_client.py @@ -95,11 +95,8 @@ def remove_omit_from_dict( ) -> typing.Dict[str, typing.Any]: if omit is None: return original - new: typing.Dict[str, typing.Any] = {} - for key, value in original.items(): - if value is not omit: - new[key] = value - return new + # optimized with dict comprehension + return {key: value for key, value in original.items() if value is not omit} def maybe_filter_request_body( @@ -108,22 +105,18 @@ def maybe_filter_request_body( omit: typing.Optional[typing.Any], ) -> typing.Optional[typing.Any]: if data is None: - return ( - jsonable_encoder(request_options.get("additional_body_parameters", {})) or {} - if request_options is not None - else None - ) + if request_options is not None: + return jsonable_encoder(request_options.get("additional_body_parameters", {})) or {} + else: + return None elif not isinstance(data, typing.Mapping): data_content = jsonable_encoder(data) else: - data_content = { - **(jsonable_encoder(remove_omit_from_dict(data, omit))), # type: ignore - **( - jsonable_encoder(request_options.get("additional_body_parameters", {})) or {} - if request_options is not None - else {} - ), - } + merged_dict = dict(jsonable_encoder(remove_omit_from_dict(data, omit))) # type: ignore + if request_options is not None: + additional = jsonable_encoder(request_options.get("additional_body_parameters", {})) or {} + merged_dict.update(additional) + data_content = merged_dict return data_content diff --git a/skyvern/client/core/jsonable_encoder.py b/skyvern/client/core/jsonable_encoder.py index afee3662d8..270138ea32 100644 --- a/skyvern/client/core/jsonable_encoder.py +++ b/skyvern/client/core/jsonable_encoder.py @@ -30,20 +30,41 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None) -> Any: custom_encoder = custom_encoder or {} + + obj_type = type(obj) if custom_encoder: - if type(obj) in custom_encoder: - return custom_encoder[type(obj)](obj) + if obj_type in custom_encoder: + return custom_encoder[obj_type](obj) else: for encoder_type, encoder_instance in custom_encoder.items(): if isinstance(obj, encoder_type): return encoder_instance(obj) + + if isinstance(obj, (str, int, float, type(None))): + return obj + if isinstance(obj, Enum): + return obj.value + if isinstance(obj, PurePath): + return str(obj) + if isinstance(obj, bytes): + return base64.b64encode(obj).decode("utf-8") + if isinstance(obj, dt.datetime): + return serialize_datetime(obj) + if isinstance(obj, dt.date): + return str(obj) + if isinstance(obj, pydantic.BaseModel): if IS_PYDANTIC_V2: encoder = getattr(obj.model_config, "json_encoders", {}) # type: ignore # Pydantic v2 else: encoder = getattr(obj.__config__, "json_encoders", {}) # type: ignore # Pydantic v1 - if custom_encoder: - encoder.update(custom_encoder) + # Avoid mutating original encoder dict + if encoder and custom_encoder: + new_encoder = dict(encoder) + new_encoder.update(custom_encoder) + encoder = new_encoder + elif custom_encoder and not encoder: + encoder = custom_encoder obj_dict = obj.dict(by_alias=True) if "__root__" in obj_dict: obj_dict = obj_dict["__root__"] @@ -53,32 +74,13 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any] if dataclasses.is_dataclass(obj): obj_dict = dataclasses.asdict(obj) # type: ignore return jsonable_encoder(obj_dict, custom_encoder=custom_encoder) - if isinstance(obj, bytes): - return base64.b64encode(obj).decode("utf-8") - if isinstance(obj, Enum): - return obj.value - if isinstance(obj, PurePath): - return str(obj) - if isinstance(obj, (str, int, float, type(None))): - return obj - if isinstance(obj, dt.datetime): - return serialize_datetime(obj) - if isinstance(obj, dt.date): - return str(obj) if isinstance(obj, dict): - encoded_dict = {} - allowed_keys = set(obj.keys()) - for key, value in obj.items(): - if key in allowed_keys: - encoded_key = jsonable_encoder(key, custom_encoder=custom_encoder) - encoded_value = jsonable_encoder(value, custom_encoder=custom_encoder) - encoded_dict[encoded_key] = encoded_value - return encoded_dict + return {jsonable_encoder(key, custom_encoder=custom_encoder): jsonable_encoder(value, custom_encoder=custom_encoder) + for key, value in obj.items()} + if isinstance(obj, (list, set, frozenset, GeneratorType, tuple)): - encoded_list = [] - for item in obj: - encoded_list.append(jsonable_encoder(item, custom_encoder=custom_encoder)) - return encoded_list + return [jsonable_encoder(item, custom_encoder=custom_encoder) for item in obj] + def fallback_serializer(o: Any) -> Any: attempt_encode = encode_by_type(o) @@ -92,9 +94,9 @@ def fallback_serializer(o: Any) -> Any: errors.append(e) try: data = vars(o) - except Exception as e: - errors.append(e) - raise ValueError(errors) from e + except Exception as e2: + errors.append(e2) + raise ValueError(errors) from e2 return jsonable_encoder(data, custom_encoder=custom_encoder) return to_jsonable_with_fallback(obj, fallback_serializer)