langchain[patch]: Update handling of deprecation warnings (#21083)

Chains should not be emitting deprecation warnings.
This commit is contained in:
Eugene Yurtsev 2024-04-30 10:30:23 -04:00 committed by GitHub
parent 5c77f45b06
commit 845d8e0025
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 50 additions and 37 deletions

View File

@ -1,6 +1,4 @@
import importlib
import os
import pathlib
import warnings
from typing import Any, Callable, Dict, Optional
@ -15,27 +13,11 @@ ALLOWED_TOP_LEVEL_PKGS = {
}
HERE = pathlib.Path(__file__).parent
ROOT = HERE.parent.parent
def _get_current_module(path: str) -> str:
"""Convert a path to a module name."""
path_as_pathlib = pathlib.Path(os.path.abspath(path))
relative_path = path_as_pathlib.relative_to(ROOT).with_suffix("")
posix_path = relative_path.as_posix()
norm_path = os.path.normpath(str(posix_path))
fully_qualified_module = norm_path.replace("/", ".")
# Strip off __init__ if present
if fully_qualified_module.endswith(".__init__"):
return fully_qualified_module[:-9]
return fully_qualified_module
def create_importer(
here: str,
package: str,
*,
module_lookup: Optional[Dict[str, str]] = None,
deprecated_lookups: Optional[Dict[str, str]] = None,
fallback_module: Optional[str] = None,
) -> Callable[[str], Any]:
"""Create a function that helps retrieve objects from their new locations.
@ -43,8 +25,11 @@ def create_importer(
The goal of this function is to help users transition from deprecated
imports to new imports.
This function will raise warnings when the old imports are used and
suggest the new imports.
The function will raise deprecation warning on loops using
deprecated_lookups or fallback_module.
Module lookups will import without deprecation warnings (used to speed
up imports from large namespaces like llms or chat models).
This function should ideally only be used with deprecated imports not with
existing imports that are valid, as in addition to raising deprecation warnings
@ -52,7 +37,7 @@ def create_importer(
loss of type information, IDE support for going to definition etc).
Args:
here: path of the current file. Use __file__
package: current package. Use __package__
module_lookup: maps name of object to the module where it is defined.
e.g.,
{
@ -60,19 +45,21 @@ def create_importer(
"langchain_community.document_loaders.my_document_loader"
)
}
deprecated_lookups: same as module look up, but will raise
deprecation warnings.
fallback_module: module to import from if the object is not found in
module_lookup or if module_lookup is not provided.
Returns:
A function that imports objects from the specified modules.
"""
current_module = _get_current_module(here)
all_module_lookup = {**(deprecated_lookups or {}), **(module_lookup or {})}
def import_by_name(name: str) -> Any:
"""Import stores from langchain_community."""
# If not in interactive env, raise warning.
if module_lookup and name in module_lookup:
new_module = module_lookup[name]
if all_module_lookup and name in all_module_lookup:
new_module = all_module_lookup[name]
if new_module.split(".")[0] not in ALLOWED_TOP_LEVEL_PKGS:
raise AssertionError(
f"Importing from {new_module} is not allowed. "
@ -92,9 +79,13 @@ def create_importer(
try:
result = getattr(module, name)
if not is_interactive_env():
if (
not is_interactive_env()
and deprecated_lookups
and name in deprecated_lookups
):
warnings.warn(
f"Importing {name} from {current_module} is deprecated. "
f"Importing {name} from {package} is deprecated. "
"Please replace the import with the following:\n"
f"from {new_module} import {name}",
category=LangChainDeprecationWarning,
@ -111,7 +102,7 @@ def create_importer(
result = getattr(module, name)
if not is_interactive_env():
warnings.warn(
f"Importing {name} from {current_module} is deprecated. "
f"Importing {name} from {package} is deprecated. "
"Please replace the import with the following:\n"
f"from {fallback_module} import {name}",
category=LangChainDeprecationWarning,
@ -123,6 +114,6 @@ def create_importer(
f"module {fallback_module} has no attribute {name}"
) from e
raise AttributeError(f"module {current_module} has no attribute {name}")
raise AttributeError(f"module {package} has no attribute {name}")
return import_by_name

View File

@ -85,7 +85,7 @@ _module_lookup = {
"TransformChain": "langchain.chains.transform",
}
importer = create_importer(__file__, module_lookup=_module_lookup)
importer = create_importer(__package__, module_lookup=_module_lookup)
def __getattr__(name: str) -> Any:

View File

@ -20,8 +20,8 @@ module_lookup = {
# Temporary code for backwards compatibility for deprecated imports.
# This will eventually be removed.
import_lookup = create_importer(
__file__,
module_lookup=module_lookup,
__package__,
deprecated_lookups=module_lookup,
)

View File

@ -3,7 +3,7 @@ from typing import Any
from langchain._api import create_importer
importer = create_importer(__file__, fallback_module="langchain_community.graphs")
importer = create_importer(__package__, fallback_module="langchain_community.graphs")
def __getattr__(name: str) -> Any:

View File

@ -35,7 +35,7 @@ from langchain.retrievers.time_weighted_retriever import (
from langchain.retrievers.web_research import WebResearchRetriever
import_lookup = create_importer(
__file__, fallback_module="langchain_community.retrievers"
__package__, fallback_module="langchain_community.retrievers"
)

View File

@ -1,12 +1,34 @@
from langchain._api.module_import import create_importer
def test_importing_module() -> None:
def test_import_from_non_deprecated_path() -> None:
"""Test importing all modules in langchain."""
module_lookup = {
"Document": "langchain_core.documents",
}
lookup = create_importer(__file__, module_lookup=module_lookup)
lookup = create_importer(__package__, module_lookup=module_lookup)
imported_doc = lookup("Document")
from langchain_core.documents import Document
assert imported_doc is Document
def test_import_from_deprecated_path() -> None:
"""Test importing all modules in langchain."""
module_lookup = {
"Document": "langchain_core.documents",
}
lookup = create_importer(__package__, deprecated_lookups=module_lookup)
imported_doc = lookup("Document")
from langchain_core.documents import Document
assert imported_doc is Document
def test_import_using_fallback_module() -> None:
"""Test import using fallback module."""
lookup = create_importer(__package__, fallback_module="langchain_core.documents")
imported_doc = lookup("Document")
from langchain_core.documents import Document