Deprecate direct access to globals like debug and verbose. (#11311)

Instead of accessing `langchain.debug`, `langchain.verbose`, or
`langchain.llm_cache`, please use the new getter/setter functions in
`langchain.globals`:
- `langchain.globals.set_debug()` and `langchain.globals.get_debug()`
- `langchain.globals.set_verbose()` and
`langchain.globals.get_verbose()`
- `langchain.globals.set_llm_cache()` and
`langchain.globals.get_llm_cache()`

Using the old globals directly will now raise a warning.

---------

Co-authored-by: Harrison Chase <hw.chase.17@gmail.com>
This commit is contained in:
Predrag Gruevski
2023-10-12 18:48:04 -04:00
committed by GitHub
parent 01b7b46908
commit 9e32120cbb
22 changed files with 479 additions and 119 deletions

View File

@@ -2,14 +2,10 @@
"""Main entrypoint into package."""
import warnings
from importlib import metadata
from typing import TYPE_CHECKING, Any, Optional
from typing import Any, Optional
from langchain._api.deprecation import surface_langchain_deprecation_warnings
if TYPE_CHECKING:
from langchain.schema import BaseCache
try:
__version__ = metadata.version(__package__)
except metadata.PackageNotFoundError:
@@ -17,10 +13,6 @@ except metadata.PackageNotFoundError:
__version__ = ""
del metadata # optional, avoids polluting the results of dir(__package__)
verbose: bool = False
debug: bool = False
llm_cache: Optional["BaseCache"] = None
def _is_interactive_env() -> bool:
"""Determine if running within IPython or Jupyter."""
@@ -29,7 +21,7 @@ def _is_interactive_env() -> bool:
return hasattr(sys, "ps2")
def _warn_on_import(name: str) -> None:
def _warn_on_import(name: str, replacement: Optional[str] = None) -> None:
"""Warn on import of deprecated module."""
if _is_interactive_env():
# No warnings for interactive environments.
@@ -37,9 +29,16 @@ def _warn_on_import(name: str) -> None:
# where users rely on auto-complete and may trigger this warning
# even if they are not using any deprecated modules
return
warnings.warn(
f"Importing {name} from langchain root module is no longer supported."
)
if replacement:
warnings.warn(
f"Importing {name} from langchain root module is no longer supported. "
f"Please use {replacement} instead."
)
else:
warnings.warn(
f"Importing {name} from langchain root module is no longer supported."
)
# Surfaces Deprecation and Pending Deprecation warnings from langchain.
@@ -328,6 +327,39 @@ def __getattr__(name: str) -> Any:
_warn_on_import(name)
return SerpAPIWrapper
elif name == "verbose":
from langchain.globals import _verbose
_warn_on_import(
name,
replacement=(
"langchain.globals.set_verbose() / langchain.globals.get_verbose()"
),
)
return _verbose
elif name == "debug":
from langchain.globals import _debug
_warn_on_import(
name,
replacement=(
"langchain.globals.set_debug() / langchain.globals.get_debug()"
),
)
return _debug
elif name == "llm_cache":
from langchain.globals import _llm_cache
_warn_on_import(
name,
replacement=(
"langchain.globals.set_llm_cache() / langchain.globals.get_llm_cache()"
),
)
return _llm_cache
else:
raise AttributeError(f"Could not find: {name}")

View File

@@ -27,7 +27,6 @@ from uuid import UUID
from tenacity import RetryCallState
import langchain
from langchain.callbacks.base import (
BaseCallbackHandler,
BaseCallbackManager,
@@ -88,7 +87,9 @@ run_collector_var: ContextVar[
def _get_debug() -> bool:
return langchain.debug
from langchain.globals import get_debug
return get_debug()
@contextmanager

View File

@@ -10,7 +10,6 @@ from typing import Any, Dict, List, Optional, Type, Union
import yaml
import langchain
from langchain.callbacks.base import BaseCallbackManager
from langchain.callbacks.manager import (
AsyncCallbackManager,
@@ -34,7 +33,9 @@ logger = logging.getLogger(__name__)
def _get_verbosity() -> bool:
return langchain.verbose
from langchain.globals import get_verbose
return get_verbose()
class Chain(RunnableSerializable[Dict[str, Any], Dict[str, Any]], ABC):
@@ -108,10 +109,10 @@ class Chain(RunnableSerializable[Dict[str, Any], Dict[str, Any]], ABC):
memory: Optional[BaseMemory] = None
"""Optional memory object. Defaults to None.
Memory is a class that gets called at the start
Memory is a class that gets called at the start
and at the end of every chain. At the start, memory loads variables and passes
them along in the chain. At the end, it saves any returned variables.
There are many different types of memory - please see memory docs
There are many different types of memory - please see memory docs
for the full catalog."""
callbacks: Callbacks = Field(default=None, exclude=True)
"""Optional list of callback handlers (or callback manager). Defaults to None.
@@ -123,7 +124,8 @@ class Chain(RunnableSerializable[Dict[str, Any], Dict[str, Any]], ABC):
"""Deprecated, use `callbacks` instead."""
verbose: bool = Field(default_factory=_get_verbosity)
"""Whether or not run in verbose mode. In verbose mode, some intermediate logs
will be printed to the console. Defaults to `langchain.verbose` value."""
will be printed to the console. Defaults to the global `verbose` value,
accessible via `langchain.globals.get_verbose()`."""
tags: Optional[List[str]] = None
"""Optional list of tags associated with the chain. Defaults to None.
These tags will be associated with each call to this chain,

View File

@@ -56,7 +56,8 @@ def create_extraction_chain(
llm: The language model to use.
prompt: The prompt to use for extraction.
verbose: Whether to run in verbose mode. In verbose mode, some intermediate
logs will be printed to the console. Defaults to `langchain.verbose` value.
logs will be printed to the console. Defaults to the global `verbose` value,
accessible via `langchain.globals.get_verbose()`.
Returns:
Chain that can be used to extract information from a passage.
@@ -88,7 +89,8 @@ def create_extraction_chain_pydantic(
llm: The language model to use.
prompt: The prompt to use for extraction.
verbose: Whether to run in verbose mode. In verbose mode, some intermediate
logs will be printed to the console. Defaults to `langchain.verbose` value.
logs will be printed to the console. Defaults to the global `verbose` value,
accessible via `langchain.globals.get_verbose()`
Returns:
Chain that can be used to extract information from a passage.

View File

@@ -50,7 +50,9 @@ from langchain.schema.runnable import RunnableConfig
def _get_verbosity() -> bool:
return langchain.verbose
from langchain.globals import get_verbose
return get_verbose()
def _generate_from_stream(stream: Iterator[ChatGenerationChunk]) -> ChatResult:

View File

@@ -0,0 +1,178 @@
"""Global values and configuration that apply to all of LangChain."""
import warnings
from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from langchain.schema import BaseCache
# DO NOT USE THESE VALUES DIRECTLY!
# Use them only via `get_<X>()` and `set_<X>()` below,
# or else your code may behave unexpectedly with other uses of these global settings:
# https://github.com/langchain-ai/langchain/pull/11311#issuecomment-1743780004
_verbose: bool = False
_debug: bool = False
_llm_cache: Optional["BaseCache"] = None
def set_verbose(value: bool) -> None:
"""Set a new value for the `verbose` global setting."""
import langchain
# We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get warnings.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message=(
"Importing verbose from langchain root module is no longer supported"
),
)
# N.B.: This is a workaround for an unfortunate quirk of Python's
# module-level `__getattr__()` implementation:
# https://github.com/langchain-ai/langchain/pull/11311#issuecomment-1743780004
#
# Remove it once `langchain.verbose` is no longer supported, and once all users
# have migrated to using `set_verbose()` here.
langchain.verbose = value
global _verbose
_verbose = value
def get_verbose() -> bool:
"""Get the value of the `verbose` global setting."""
import langchain
# We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get warnings.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message=(
"Importing verbose from langchain root module is no longer supported"
),
)
# N.B.: This is a workaround for an unfortunate quirk of Python's
# module-level `__getattr__()` implementation:
# https://github.com/langchain-ai/langchain/pull/11311#issuecomment-1743780004
#
# Remove it once `langchain.verbose` is no longer supported, and once all users
# have migrated to using `set_verbose()` here.
#
# In the meantime, the `verbose` setting is considered True if either the old
# or the new value are True. This accommodates users who haven't migrated
# to using `set_verbose()` yet. Those users are getting deprecation warnings
# directing them to use `set_verbose()` when they import `langhchain.verbose`.
old_verbose = langchain.verbose
global _verbose
return _verbose or old_verbose
def set_debug(value: bool) -> None:
"""Set a new value for the `debug` global setting."""
import langchain
# We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get warnings.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message="Importing debug from langchain root module is no longer supported",
)
# N.B.: This is a workaround for an unfortunate quirk of Python's
# module-level `__getattr__()` implementation:
# https://github.com/langchain-ai/langchain/pull/11311#issuecomment-1743780004
#
# Remove it once `langchain.debug` is no longer supported, and once all users
# have migrated to using `set_debug()` here.
langchain.debug = value
global _debug
_debug = value
def get_debug() -> bool:
"""Get the value of the `debug` global setting."""
import langchain
# We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get warnings.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message="Importing debug from langchain root module is no longer supported",
)
# N.B.: This is a workaround for an unfortunate quirk of Python's
# module-level `__getattr__()` implementation:
# https://github.com/langchain-ai/langchain/pull/11311#issuecomment-1743780004
#
# Remove it once `langchain.debug` is no longer supported, and once all users
# have migrated to using `set_debug()` here.
#
# In the meantime, the `debug` setting is considered True if either the old
# or the new value are True. This accommodates users who haven't migrated
# to using `set_debug()` yet. Those users are getting deprecation warnings
# directing them to use `set_debug()` when they import `langhchain.debug`.
old_debug = langchain.debug
global _debug
return _debug or old_debug
def set_llm_cache(value: "BaseCache") -> None:
"""Set a new LLM cache, overwriting the previous value, if any."""
import langchain
# We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get warnings.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message=(
"Importing llm_cache from langchain root module is no longer supported"
),
)
# N.B.: This is a workaround for an unfortunate quirk of Python's
# module-level `__getattr__()` implementation:
# https://github.com/langchain-ai/langchain/pull/11311#issuecomment-1743780004
#
# Remove it once `langchain.llm_cache` is no longer supported, and
# once all users have migrated to using `set_llm_cache()` here.
langchain.llm_cache = value
global _llm_cache
_llm_cache = value
def get_llm_cache() -> "BaseCache":
"""Get the value of the `llm_cache` global setting."""
import langchain
# We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get warnings.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message=(
"Importing llm_cache from langchain root module is no longer supported"
),
)
# N.B.: This is a workaround for an unfortunate quirk of Python's
# module-level `__getattr__()` implementation:
# https://github.com/langchain-ai/langchain/pull/11311#issuecomment-1743780004
#
# Remove it once `langchain.llm_cache` is no longer supported, and
# once all users have migrated to using `set_llm_cache()` here.
#
# In the meantime, the `llm_cache` setting returns whichever of
# its two backing sources is truthy (not `None` and non-empty),
# or the old value if both are falsy. This accommodates users
# who haven't migrated to using `set_llm_cache()` yet.
# Those users are getting deprecation warnings directing them
# to use `set_llm_cache()` when they import `langhchain.llm_cache`.
old_llm_cache = langchain.llm_cache
global _llm_cache
return _llm_cache or old_llm_cache

View File

@@ -66,7 +66,9 @@ logger = logging.getLogger(__name__)
def _get_verbosity() -> bool:
return langchain.verbose
from langchain.globals import get_verbose
return get_verbose()
@functools.lru_cache

View File

@@ -0,0 +1,121 @@
from langchain.globals import get_debug, get_verbose, set_debug, set_verbose
def test_debug_is_settable_directly() -> None:
import langchain
from langchain.callbacks.manager import _get_debug
previous_value = langchain.debug
previous_fn_reading = _get_debug()
assert previous_value == previous_fn_reading
# Flip the value of the flag.
langchain.debug = not previous_value
new_value = langchain.debug
new_fn_reading = _get_debug()
try:
# We successfully changed the value of `debug`.
assert new_value != previous_value
# If we access `debug` via a function used elsewhere in langchain,
# it also sees the same new value.
assert new_value == new_fn_reading
# If we access `debug` via `get_debug()` we also get the same value.
assert new_value == get_debug()
finally:
# Make sure we don't alter global state, even if the test fails.
# Always reset `debug` to the value it had before.
set_debug(previous_value)
def test_debug_is_settable_via_setter() -> None:
from langchain import globals
from langchain.callbacks.manager import _get_debug
previous_value = globals._debug
previous_fn_reading = _get_debug()
assert previous_value == previous_fn_reading
# Flip the value of the flag.
set_debug(not previous_value)
new_value = globals._debug
new_fn_reading = _get_debug()
try:
# We successfully changed the value of `debug`.
assert new_value != previous_value
# If we access `debug` via a function used elsewhere in langchain,
# it also sees the same new value.
assert new_value == new_fn_reading
# If we access `debug` via `get_debug()` we also get the same value.
assert new_value == get_debug()
finally:
# Make sure we don't alter global state, even if the test fails.
# Always reset `debug` to the value it had before.
set_debug(previous_value)
def test_verbose_is_settable_directly() -> None:
import langchain
from langchain.chains.base import _get_verbosity
previous_value = langchain.verbose
previous_fn_reading = _get_verbosity()
assert previous_value == previous_fn_reading
# Flip the value of the flag.
langchain.verbose = not previous_value
new_value = langchain.verbose
new_fn_reading = _get_verbosity()
try:
# We successfully changed the value of `verbose`.
assert new_value != previous_value
# If we access `verbose` via a function used elsewhere in langchain,
# it also sees the same new value.
assert new_value == new_fn_reading
# If we access `verbose` via `get_verbose()` we also get the same value.
assert new_value == get_verbose()
finally:
# Make sure we don't alter global state, even if the test fails.
# Always reset `verbose` to the value it had before.
set_verbose(previous_value)
def test_verbose_is_settable_via_setter() -> None:
from langchain import globals
from langchain.chains.base import _get_verbosity
previous_value = globals._verbose
previous_fn_reading = _get_verbosity()
assert previous_value == previous_fn_reading
# Flip the value of the flag.
set_verbose(not previous_value)
new_value = globals._verbose
new_fn_reading = _get_verbosity()
try:
# We successfully changed the value of `verbose`.
assert new_value != previous_value
# If we access `verbose` via a function used elsewhere in langchain,
# it also sees the same new value.
assert new_value == new_fn_reading
# If we access `verbose` via `get_verbose()` we also get the same value.
assert new_value == get_verbose()
finally:
# Make sure we don't alter global state, even if the test fails.
# Always reset `verbose` to the value it had before.
set_verbose(previous_value)