Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StructuredTool.from_function does not support functools.partial #27500

Open
5 tasks done
coolbeevip opened this issue Oct 21, 2024 · 1 comment
Open
5 tasks done

StructuredTool.from_function does not support functools.partial #27500

coolbeevip opened this issue Oct 21, 2024 · 1 comment
Labels
🤖:bug Related to a bug, vulnerability, unexpected error with an existing feature

Comments

@coolbeevip
Copy link
Contributor

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangChain documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).

Example Code

def test_structured_tool_from_function_partial() -> None:
    """Test that structured tools can be created from a partial function."""

    def func(bar: str, baz: str=None) -> str:
        """Docstring

        Args:
            bar: str
            baz: str
        """
        return bar + baz

    structured_tool = StructuredTool.from_function(
        name="tool",
        description="A tool",
        func=partial(func, baz="foo"),
    )
    assert structured_tool.invoke({"bar": "bar"}) == "barfoo"

Error Message and Stack Trace (if applicable)

tests/unit_tests/test_tools.py:484 (test_structured_tool_from_function_partial)
def test_structured_tool_from_function_partial() -> None:
        """Test that structured tools can be created from a partial function."""
    
        def func(bar: str, baz: str=None) -> str:
            """Docstring
    
            Args:
                bar: str
                baz: str
            """
            return bar + baz
    
>       structured_tool = StructuredTool.from_function(
            name="tool",
            description="A tool",
            func=partial(func, baz="foo"),
        )

test_tools.py:497: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../langchain_core/tools/structured.py:181: in from_function
    args_schema = create_schema_from_function(
../../langchain_core/tools/base.py:249: in create_schema_from_function
    validated = validate_arguments(func, config=_SchemaConfig)  # type: ignore
../../../../venv/lib/python3.11/site-packages/pydantic/deprecated/decorator.py:64: in validate_arguments
    return validate(func)
../../../../venv/lib/python3.11/site-packages/pydantic/deprecated/decorator.py:51: in validate
    vd = ValidatedFunction(_func, config)
../../../../venv/lib/python3.11/site-packages/pydantic/deprecated/decorator.py:94: in __init__
    type_hints = _typing_extra.get_type_hints(function, include_extras=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = functools.partial(<function test_structured_tool_from_function_partial.<locals>.func at 0x119bd04a0>, baz='foo')
globalns = {}, localns = {}, include_extras = True

    def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
        """Return type hints for an object.
    
        This is often the same as obj.__annotations__, but it handles
        forward references encoded as string literals and recursively replaces all
        'Annotated[T, ...]' with 'T' (unless 'include_extras=True').
    
        The argument may be a module, class, method, or function. The annotations
        are returned as a dictionary. For classes, annotations include also
        inherited members.
    
        TypeError is raised if the argument is not of a type that can contain
        annotations, and an empty dictionary is returned if no annotations are
        present.
    
        BEWARE -- the behavior of globalns and localns is counterintuitive
        (unless you are familiar with how eval() and exec() work).  The
        search order is locals first, then globals.
    
        - If no dict arguments are passed, an attempt is made to use the
          globals from obj (or the respective module's globals for classes),
          and these are also used as the locals.  If the object does not appear
          to have globals, an empty dictionary is used.  For classes, the search
          order is globals first then locals.
    
        - If one dict argument is passed, it is used for both globals and
          locals.
    
        - If two dict arguments are passed, they specify globals and
          locals, respectively.
        """
        if getattr(obj, '__no_type_check__', None):
            return {}
        # Classes require a special treatment.
        if isinstance(obj, type):
            hints = {}
            for base in reversed(obj.__mro__):
                if globalns is None:
                    base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {})
                else:
                    base_globals = globalns
                ann = base.__dict__.get('__annotations__', {})
                if isinstance(ann, types.GetSetDescriptorType):
                    ann = {}
                base_locals = dict(vars(base)) if localns is None else localns
                if localns is None and globalns is None:
                    # This is surprising, but required.  Before Python 3.10,
                    # get_type_hints only evaluated the globalns of
                    # a class.  To maintain backwards compatibility, we reverse
                    # the globalns and localns order so that eval() looks into
                    # *base_globals* first rather than *base_locals*.
                    # This only affects ForwardRefs.
                    base_globals, base_locals = base_locals, base_globals
                for name, value in ann.items():
                    if value is None:
                        value = type(None)
                    if isinstance(value, str):
                        value = ForwardRef(value, is_argument=False, is_class=True)
                    value = _eval_type(value, base_globals, base_locals)
                    hints[name] = value
            return hints if include_extras else {k: _strip_annotations(t) for k, t in hints.items()}
    
        if globalns is None:
            if isinstance(obj, types.ModuleType):
                globalns = obj.__dict__
            else:
                nsobj = obj
                # Find globalns for the unwrapped object.
                while hasattr(nsobj, '__wrapped__'):
                    nsobj = nsobj.__wrapped__
                globalns = getattr(nsobj, '__globals__', {})
            if localns is None:
                localns = globalns
        elif localns is None:
            localns = globalns
        hints = getattr(obj, '__annotations__', None)
        if hints is None:
            # Return empty annotations for something that _could_ have them.
            if isinstance(obj, _allowed_types):
                return {}
            else:
>               raise TypeError('{!r} is not a module, class, method, '
                                'or function.'.format(obj))
E               TypeError: functools.partial(<function test_structured_tool_from_function_partial.<locals>.func at 0x119bd04a0>, baz='foo') is not a module, class, method, or function.

/Users/xxx/.pyenv/versions/3.11.4/lib/python3.11/typing.py:2359: TypeError

Description

A value to source_function must be assigned based on the type of the func object in the StructuredTool.from_function method.

System Info

System Information

OS: Darwin
OS Version: Darwin Kernel Version 23.3.0: Wed Dec 20 21:30:44 PST 2023; root:xnu-10002.81.5~7/RELEASE_ARM64_T6000
Python Version: 3.11.4 (main, Sep 6 2023, 14:18:32) [Clang 13.1.6 (clang-1316.0.21.2.5)]

Package Information

langchain_core: 0.3.11
langchain: 0.1.16
langchain_community: 0.0.34
langsmith: 0.1.128
langchain_openai: 0.1.3
langchain_text_splitters: 0.3.0

Optional packages not installed

langgraph
langserve

Other Dependencies

aiohttp: 3.10.6
aiosqlite: Installed. No version info available.
aleph-alpha-client: Installed. No version info available.
anthropic: 0.3.11
arxiv: Installed. No version info available.
assemblyai: Installed. No version info available.
async-timeout: Installed. No version info available.
atlassian-python-api: Installed. No version info available.
azure-ai-documentintelligence: Installed. No version info available.
azure-ai-formrecognizer: Installed. No version info available.
azure-ai-textanalytics: Installed. No version info available.
azure-cognitiveservices-speech: Installed. No version info available.
azure-core: Installed. No version info available.
azure-cosmos: Installed. No version info available.
azure-identity: Installed. No version info available.
azure-search-documents: Installed. No version info available.
beautifulsoup4: 4.12.3
bibtexparser: Installed. No version info available.
cassio: 0.1.6
chardet: Installed. No version info available.
clarifai: Installed. No version info available.
cloudpickle: Installed. No version info available.
cohere: Installed. No version info available.
couchbase: Installed. No version info available.
dashvector: Installed. No version info available.
databricks-vectorsearch: Installed. No version info available.
dataclasses-json: 0.6.4
datasets: Installed. No version info available.
dgml-utils: Installed. No version info available.
docarray[hnswlib]: Installed. No version info available.
elasticsearch: Installed. No version info available.
esprima: Installed. No version info available.
faiss-cpu: Installed. No version info available.
feedparser: Installed. No version info available.
fireworks-ai: 0.9.0
friendli-client: Installed. No version info available.
geopandas: Installed. No version info available.
gitpython: Installed. No version info available.
google-cloud-documentai: Installed. No version info available.
gql: Installed. No version info available.
gradientai: Installed. No version info available.
hdbcli: Installed. No version info available.
hologres-vector: Installed. No version info available.
html2text: Installed. No version info available.
httpx: 0.27.2
httpx-sse: 0.4.0
huggingface_hub: 0.25.2
javelin-sdk: Installed. No version info available.
jinja2: 3.1.4
jq: Installed. No version info available.
jsonpatch: 1.33
jsonschema: 4.23.0
lxml: Installed. No version info available.
manifest-ml: Installed. No version info available.
markdownify: Installed. No version info available.
motor: Installed. No version info available.
msal: Installed. No version info available.
mwparserfromhell: Installed. No version info available.
mwxml: Installed. No version info available.
newspaper3k: Installed. No version info available.
nlpcloud: Installed. No version info available.
numexpr: Installed. No version info available.
numpy: 1.26.4
nvidia-riva-client: Installed. No version info available.
oci: Installed. No version info available.
openai: 1.13.3
openapi-pydantic: Installed. No version info available.
openlm: Installed. No version info available.
oracle-ads: Installed. No version info available.
orjson: 3.10.7
packaging: 24.1
pandas: 2.0.3
pdfminer-six: Installed. No version info available.
pgvector: Installed. No version info available.
praw: Installed. No version info available.
premai: Installed. No version info available.
psychicapi: Installed. No version info available.
py-trello: Installed. No version info available.
pydantic: 2.9.2
pyjwt: Installed. No version info available.
pymupdf: Installed. No version info available.
pypdf: Installed. No version info available.
pypdfium2: Installed. No version info available.
pyspark: Installed. No version info available.
PyYAML: 6.0.2
qdrant-client: Installed. No version info available.
rank-bm25: Installed. No version info available.
rapidfuzz: Installed. No version info available.
rapidocr-onnxruntime: Installed. No version info available.
rdflib: Installed. No version info available.
requests: 2.32.3
requests-toolbelt: Installed. No version info available.
rspace_client: Installed. No version info available.
scikit-learn: Installed. No version info available.
sentence-transformers: Installed. No version info available.
SQLAlchemy: 2.0.35
sqlite-vss: Installed. No version info available.
streamlit: Installed. No version info available.
sympy: 1.13.3
telethon: Installed. No version info available.
tenacity: 8.5.0
tidb-vector: Installed. No version info available.
tiktoken: 0.5.2
timescale-vector: Installed. No version info available.
torch: Installed. No version info available.
tqdm: 4.66.5
transformers: Installed. No version info available.
tree-sitter: Installed. No version info available.
tree-sitter-languages: Installed. No version info available.
typer: Installed. No version info available.
typing-extensions: 4.12.2
upstash-redis: Installed. No version info available.
vdms: 0.0.20
xata: Installed. No version info available.
xmltodict: Installed. No version info available.

@dosubot dosubot bot added the 🤖:bug Related to a bug, vulnerability, unexpected error with an existing feature label Oct 21, 2024
@Emilyho11
Copy link

Hello, this issue looks interesting. Could my group and I take a look at it? Is there any additional information you have found in the meantime?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤖:bug Related to a bug, vulnerability, unexpected error with an existing feature
Projects
None yet
Development

No branches or pull requests

2 participants