Skip to content

Commit 89e758e

Browse files
authored
Merge pull request #6 from comfuture/PEP-0727
Implement PEP-0727 Doc in Annotation metadata
2 parents bff6696 + 5d73f96 commit 89e758e

File tree

4 files changed

+103
-8
lines changed

4 files changed

+103
-8
lines changed

function_schema/core.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,50 @@
1212
else:
1313
UnionType = typing.Union # type: ignore
1414

15+
try:
16+
from typing import Doc
17+
except ImportError:
18+
try:
19+
from typing_extensions import Doc
20+
except ImportError:
21+
class Doc:
22+
def __init__(self, documentation: str, /):
23+
self.documentation = documentation
24+
25+
__all__ = ("get_function_schema", "guess_type", "Doc")
26+
27+
def is_doc_meta(obj):
28+
"""
29+
Check if the given object is a documentation object.
30+
Parameters:
31+
obj (object): The object to be checked.
32+
Returns:
33+
bool: True if the object is a documentation object, False otherwise.
34+
35+
Example:
36+
>>> is_doc_meta(Doc("This is a documentation object"))
37+
True
38+
"""
39+
return getattr(obj, '__class__') == Doc and hasattr(obj, 'documentation')
40+
41+
def unwrap_doc(obj: typing.Union[Doc, str]):
42+
"""
43+
Get the documentation string from the given object.
44+
Parameters:
45+
obj (Doc | str): The object to get the documentation string from.
46+
Returns:
47+
str: The documentation string.
48+
49+
Example:
50+
>>> unwrap_doc(Doc("This is a documentation object"))
51+
'This is a documentation object'
52+
>>> unwrap_doc("This is a documentation string")
53+
'This is a documentation string'
54+
"""
55+
if is_doc_meta(obj):
56+
return obj.documentation
57+
return str(obj)
58+
1559

1660
def get_function_schema(
1761
func: typing.Annotated[typing.Callable, "The function to get the schema for"],
@@ -83,7 +127,7 @@ def get_function_schema(
83127

84128
# find description in param_args tuple
85129
description = next(
86-
(arg for arg in param_args if isinstance(arg, str)),
130+
(unwrap_doc(arg) for arg in param_args if isinstance(arg, (Doc, str))),
87131
f"The {name} parameter",
88132
)
89133

pyproject.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ classifiers = [
1717
"Programming Language :: Python :: 3.9",
1818
]
1919

20-
[project.optional-dependencies]
21-
test = ["pytest"]
22-
2320
[project.urls]
2421
Homepage = "https://github.com/comfuture/function-schema"
2522
Repository = "https://github.com/comfuture/function-schema"
@@ -30,3 +27,9 @@ function_schema = "function_schema.cli:main"
3027
[build-system]
3128
requires = ["flit_core >=3.9,<4"]
3229
build-backend = "flit_core.buildapi"
30+
31+
[tool.uv]
32+
dev-dependencies = [
33+
"pytest>=8.3.2",
34+
"typing-extensions>=4.12.2",
35+
]

test/test_pep_0727_doc.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import Annotated
2+
from enum import Enum
3+
from function_schema.core import get_function_schema, Doc
4+
5+
6+
def test_docs_in_annotation():
7+
"""Test a function with annotations with Doc"""
8+
def func1(a: Annotated[int, Doc("An integer parameter")]):
9+
"""My function"""
10+
...
11+
12+
schema = get_function_schema(func1)
13+
assert schema["name"] == "func1", "Function name should be func1"
14+
assert schema["description"] == "My function", "Function description should be there"
15+
assert schema["parameters"]["properties"]["a"]["type"] == "number", "parameter a should be an integer"
16+
assert schema["parameters"]["properties"]["a"]["description"] == "An integer parameter", "parameter a should have a description"
17+
assert schema["parameters"]["required"] == [
18+
"a"], "parameter a should be required"
19+
20+
21+
def test_doc_in_nth_args():
22+
"""Test a function with annotations with Doc in nth args"""
23+
def func1(a: Annotated[str, Enum("Candidates", "a b c"), Doc("A string parameter")]):
24+
"""My function"""
25+
...
26+
27+
schema = get_function_schema(func1)
28+
assert schema["name"] == "func1", "Function name should be func1"
29+
assert schema["description"] == "My function", "Function description should be there"
30+
assert schema["parameters"]["properties"]["a"]["type"] == "string", "parameter a should be an string"
31+
assert schema["parameters"]["properties"]["a"]["description"] == "A string parameter", "parameter a should have a description"
32+
assert schema["parameters"]["properties"]["a"]["enum"] == [
33+
"a", "b", "c"], "parameter a should have enum values"

uv.lock

Lines changed: 19 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)