diff --git a/src/humanloop/decorators/tool.py b/src/humanloop/decorators/tool.py index 0662041b..2752d017 100644 --- a/src/humanloop/decorators/tool.py +++ b/src/humanloop/decorators/tool.py @@ -213,7 +213,7 @@ def _build_function_parameters_property(func) -> _JSONSchemaFunctionParameters: ) -if sys.version_info >= (3, 10): +if sys.version_info >= (3, 11): _PRIMITIVE_TYPES = Union[ str, int, @@ -223,7 +223,7 @@ def _build_function_parameters_property(func) -> _JSONSchemaFunctionParameters: Ellipsis, # type: ignore ] else: - # Ellipsis not supported in typing module before Python 3.10 + # Ellipsis not supported as type before Python 3.11 _PRIMITIVE_TYPES = Union[ str, int, diff --git a/tests/decorators/test_tool_decorator.py b/tests/decorators/test_tool_decorator.py index 34b330ef..2f4db209 100644 --- a/tests/decorators/test_tool_decorator.py +++ b/tests/decorators/test_tool_decorator.py @@ -463,106 +463,101 @@ def calculator(operation: str, num1: float, num2: float) -> float: assert hl_file_higher_order_fn["tool"]["source_code"] == hl_file_decorated_fn["tool"]["source_code"] # type: ignore -def test_python310_syntax( - opentelemetry_test_configuration: tuple[Tracer, InMemorySpanExporter], -): - if sys.version_info < (3, 10): - pytest.skip("Requires Python 3.10") - # GIVEN an OTel configuration - tracer, _ = opentelemetry_test_configuration +if sys.version_info >= (3, 10): + # Testing that function parsing for Tool decorator + # works with Python 3.10 and above syntax - # GIVEN a function annotated with @tool where a parameter uses `|` for Optional - @tool(opentelemetry_tracer=tracer) - def calculator(a: float, b: float | None = None) -> float: - # NOTE: dummy function, only testing its signature not correctness - if a is None: - a = 0 - return a + b # type: ignore + def test_python310_syntax( + opentelemetry_test_configuration: tuple[Tracer, InMemorySpanExporter], + ): + # GIVEN an OTel configuration + tracer, _ = opentelemetry_test_configuration - # WHEN building the Tool kernel - # THEN the JSON schema is correct - assert calculator.json_schema == { - "description": "", - "name": "calculator", - "parameters": { - "properties": { - "a": {"type": "number"}, - "b": {"type": ["number", "null"]}, + # GIVEN a function annotated with @tool where a parameter uses `|` for Optional + @tool(opentelemetry_tracer=tracer) + def calculator(a: float, b: float | None = None) -> float: + # NOTE: dummy function, only testing its signature not correctness + if a is None: + a = 0 + return a + b # type: ignore + + # WHEN building the Tool kernel + # THEN the JSON schema is correct + assert calculator.json_schema == { + "description": "", + "name": "calculator", + "parameters": { + "properties": { + "a": {"type": "number"}, + "b": {"type": ["number", "null"]}, + }, + "required": ("a",), + "type": "object", + "additionalProperties": False, }, - "required": ("a",), - "type": "object", - "additionalProperties": False, - }, - "strict": True, - } - - Validator.check_schema(calculator.json_schema) - - -def test_python310_union_syntax( - opentelemetry_test_configuration: tuple[Tracer, InMemorySpanExporter], -): - if sys.version_info < (3, 10): - pytest.skip("Requires Python 3.10") + "strict": True, + } - # GIVEN an OTel configuration - tracer, _ = opentelemetry_test_configuration + Validator.check_schema(calculator.json_schema) - # GIVEN a function annotated with @tool where a parameter uses `|` for Union - @tool(opentelemetry_tracer=tracer) - def calculator(a: float, b: float | int | str) -> float: - # NOTE: dummy function, only testing its signature not correctness - return a + b # type: ignore + def test_python310_union_syntax( + opentelemetry_test_configuration: tuple[Tracer, InMemorySpanExporter], + ): + # GIVEN an OTel configuration + tracer, _ = opentelemetry_test_configuration - # WHEN building the Tool kernel - # THEN the JSON schema is correct - assert calculator.json_schema == { - "description": "", - "name": "calculator", - "parameters": { - "properties": { - "a": {"type": "number"}, - "b": {"anyOf": [{"type": "number"}, {"type": "integer"}, {"type": "string"}]}, + # GIVEN a function annotated with @tool where a parameter uses `|` for Union + @tool(opentelemetry_tracer=tracer) + def calculator(a: float, b: float | int | str) -> float: + # NOTE: dummy function, only testing its signature not correctness + return a + b # type: ignore + + # WHEN building the Tool kernel + # THEN the JSON schema is correct + assert calculator.json_schema == { + "description": "", + "name": "calculator", + "parameters": { + "properties": { + "a": {"type": "number"}, + "b": {"anyOf": [{"type": "number"}, {"type": "integer"}, {"type": "string"}]}, + }, + "required": ("a", "b"), + "type": "object", + "additionalProperties": False, }, - "required": ("a", "b"), - "type": "object", - "additionalProperties": False, - }, - "strict": True, - } - - Validator.check_schema(calculator.json_schema) - + "strict": True, + } -def test_python_list_ellipsis( - opentelemetry_test_configuration: tuple[Tracer, InMemorySpanExporter], -): - if sys.version_info < (3, 10): - pytest.skip("Requires Python 3.10") - # GIVEN an OTel configuration - tracer, _ = opentelemetry_test_configuration + Validator.check_schema(calculator.json_schema) - # GIVEN a function annotated with @tool where a parameter uses `...` - @tool(opentelemetry_tracer=tracer) - def calculator(b: ...) -> float | None: # type: ignore - # NOTE: dummy function, only testing its signature not correctness - if isinstance(b, list): - return sum(b) - return None + def test_python_list_ellipsis( + opentelemetry_test_configuration: tuple[Tracer, InMemorySpanExporter], + ): + # GIVEN an OTel configuration + tracer, _ = opentelemetry_test_configuration - # WHEN building the Tool kernel - # THEN the JSON schema is correct - assert calculator.json_schema == { - "description": "", - "name": "calculator", - "parameters": { - "properties": { - # THEN b is of any type - "b": {"type": ["string", "integer", "number", "boolean", "object", "array", "null"]}, + # GIVEN a function annotated with @tool where a parameter uses `...` + @tool(opentelemetry_tracer=tracer) + def calculator(b: ...) -> float | None: # type: ignore + # NOTE: dummy function, only testing its signature not correctness + if isinstance(b, list): + return sum(b) + return None + + # WHEN building the Tool kernel + # THEN the JSON schema is correct + assert calculator.json_schema == { + "description": "", + "name": "calculator", + "parameters": { + "properties": { + # THEN b is of any type + "b": {"type": ["string", "integer", "number", "boolean", "object", "array", "null"]}, + }, + "required": ("b",), + "type": "object", + "additionalProperties": False, }, - "required": ("b",), - "type": "object", - "additionalProperties": False, - }, - "strict": True, - } + "strict": True, + }