Skip to content

Commit

Permalink
[Python] Cache env var check (#971)
Browse files Browse the repository at this point in the history
  • Loading branch information
hinthornw authored Sep 4, 2024
1 parent 12d3c86 commit 710c9fe
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 16 deletions.
2 changes: 1 addition & 1 deletion python/langsmith/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,7 @@ def _run_transform(

@staticmethod
def _insert_runtime_env(runs: Sequence[dict]) -> None:
runtime_env = ls_env.get_runtime_and_metrics()
runtime_env = ls_env.get_runtime_environment()
for run_create in runs:
run_extra = cast(dict, run_create.setdefault("extra", {}))
# update runtime
Expand Down
2 changes: 2 additions & 0 deletions python/langsmith/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ def is_base_message_like(obj: object) -> bool:
)


@functools.lru_cache(maxsize=100)
def get_env_var(
name: str,
default: Optional[str] = None,
Expand Down Expand Up @@ -379,6 +380,7 @@ def get_env_var(
return default


@functools.lru_cache(maxsize=1)
def get_tracer_project(return_default_value=True) -> Optional[str]:
"""Get the project name for a LangSmith tracer."""
return os.environ.get(
Expand Down
2 changes: 1 addition & 1 deletion python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "langsmith"
version = "0.1.111"
version = "0.1.112"
description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
authors = ["LangChain <[email protected]>"]
license = "MIT"
Expand Down
7 changes: 6 additions & 1 deletion python/tests/integration_tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@

from langsmith.client import ID_TYPE, Client
from langsmith.schemas import DataType
from langsmith.utils import LangSmithConnectionError, LangSmithError
from langsmith.utils import (
LangSmithConnectionError,
LangSmithError,
get_env_var,
)


def wait_for(
Expand Down Expand Up @@ -351,6 +355,7 @@ def test_persist_update_run(langchain_client: Client) -> None:

@pytest.mark.parametrize("uri", ["http://localhost:1981", "http://api.langchain.minus"])
def test_error_surfaced_invalid_uri(monkeypatch: pytest.MonkeyPatch, uri: str) -> None:
get_env_var.cache_clear()
monkeypatch.setenv("LANGCHAIN_ENDPOINT", uri)
monkeypatch.setenv("LANGCHAIN_API_KEY", "test")
client = Client()
Expand Down
14 changes: 14 additions & 0 deletions python/tests/unit_tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ def test__is_langchain_hosted() -> None:
assert _is_langchain_hosted("https://dev.api.smith.langchain.com")


def _clear_env_cache():
ls_utils.get_env_var.cache_clear()


def test_validate_api_url(monkeypatch: pytest.MonkeyPatch) -> None:
# Scenario 1: Both LANGCHAIN_ENDPOINT and LANGSMITH_ENDPOINT
# are set, but api_url is not
_clear_env_cache()
monkeypatch.setenv("LANGCHAIN_ENDPOINT", "https://api.smith.langchain-endpoint.com")
monkeypatch.setenv("LANGSMITH_ENDPOINT", "https://api.smith.langsmith-endpoint.com")

Expand All @@ -65,20 +70,23 @@ def test_validate_api_url(monkeypatch: pytest.MonkeyPatch) -> None:

# Scenario 2: Both LANGCHAIN_ENDPOINT and LANGSMITH_ENDPOINT
# are set, and api_url is set
_clear_env_cache()
monkeypatch.setenv("LANGCHAIN_ENDPOINT", "https://api.smith.langchain-endpoint.com")
monkeypatch.setenv("LANGSMITH_ENDPOINT", "https://api.smith.langsmith-endpoint.com")

client = Client(api_url="https://api.smith.langchain.com", api_key="123")
assert client.api_url == "https://api.smith.langchain.com"

# Scenario 3: LANGCHAIN_ENDPOINT is set, but LANGSMITH_ENDPOINT is not
_clear_env_cache()
monkeypatch.setenv("LANGCHAIN_ENDPOINT", "https://api.smith.langchain-endpoint.com")
monkeypatch.delenv("LANGSMITH_ENDPOINT", raising=False)

client = Client()
assert client.api_url == "https://api.smith.langchain-endpoint.com"

# Scenario 4: LANGCHAIN_ENDPOINT is not set, but LANGSMITH_ENDPOINT is set
_clear_env_cache()
monkeypatch.delenv("LANGCHAIN_ENDPOINT", raising=False)
monkeypatch.setenv("LANGSMITH_ENDPOINT", "https://api.smith.langsmith-endpoint.com")

Expand All @@ -89,6 +97,7 @@ def test_validate_api_url(monkeypatch: pytest.MonkeyPatch) -> None:
def test_validate_api_key(monkeypatch: pytest.MonkeyPatch) -> None:
# Scenario 1: Both LANGCHAIN_API_KEY and LANGSMITH_API_KEY are set,
# but api_key is not
_clear_env_cache()
monkeypatch.setenv("LANGCHAIN_API_KEY", "env_langchain_api_key")
monkeypatch.setenv("LANGSMITH_API_KEY", "env_langsmith_api_key")

Expand All @@ -97,6 +106,7 @@ def test_validate_api_key(monkeypatch: pytest.MonkeyPatch) -> None:

# Scenario 2: Both LANGCHAIN_API_KEY and LANGSMITH_API_KEY are set,
# and api_key is set
_clear_env_cache()
monkeypatch.setenv("LANGCHAIN_API_KEY", "env_langchain_api_key")
monkeypatch.setenv("LANGSMITH_API_KEY", "env_langsmith_api_key")

Expand All @@ -111,6 +121,7 @@ def test_validate_api_key(monkeypatch: pytest.MonkeyPatch) -> None:
assert client.api_key == "env_langchain_api_key"

# Scenario 4: LANGCHAIN_API_KEY is not set, but LANGSMITH_API_KEY is set
_clear_env_cache()
monkeypatch.delenv("LANGCHAIN_API_KEY", raising=False)
monkeypatch.setenv("LANGSMITH_API_KEY", "env_langsmith_api_key")

Expand All @@ -119,6 +130,7 @@ def test_validate_api_key(monkeypatch: pytest.MonkeyPatch) -> None:


def test_validate_multiple_urls(monkeypatch: pytest.MonkeyPatch) -> None:
_clear_env_cache()
monkeypatch.setenv("LANGCHAIN_ENDPOINT", "https://api.smith.langchain-endpoint.com")
monkeypatch.setenv("LANGSMITH_ENDPOINT", "https://api.smith.langsmith-endpoint.com")
monkeypatch.setenv("LANGSMITH_RUNS_ENDPOINTS", "{}")
Expand Down Expand Up @@ -149,6 +161,7 @@ def test_validate_multiple_urls(monkeypatch: pytest.MonkeyPatch) -> None:


def test_headers(monkeypatch: pytest.MonkeyPatch) -> None:
_clear_env_cache()
monkeypatch.delenv("LANGCHAIN_API_KEY", raising=False)
with patch.dict("os.environ", {}, clear=True):
client = Client(api_url="http://localhost:1984", api_key="123")
Expand All @@ -161,6 +174,7 @@ def test_headers(monkeypatch: pytest.MonkeyPatch) -> None:

@mock.patch("langsmith.client.requests.Session")
def test_upload_csv(mock_session_cls: mock.Mock) -> None:
_clear_env_cache()
dataset_id = str(uuid.uuid4())
example_1 = ls_schemas.Example(
id=str(uuid.uuid4()),
Expand Down
11 changes: 3 additions & 8 deletions python/tests/unit_tests/test_run_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,15 @@
import time
import uuid
import warnings
from typing import (
Any,
AsyncGenerator,
Generator,
Optional,
Set,
cast,
)
from typing import Any, AsyncGenerator, Generator, Optional, Set, cast
from unittest.mock import MagicMock, patch

import pytest

import langsmith
from langsmith import Client
from langsmith import schemas as ls_schemas
from langsmith import utils as ls_utils
from langsmith.run_helpers import (
_get_inputs,
as_runnable,
Expand Down Expand Up @@ -1333,6 +1327,7 @@ async def my_function(a: int) -> AsyncGenerator[int, None]:
@pytest.mark.parametrize("env_var", [True, False])
@pytest.mark.parametrize("context", [True, False, None])
async def test_trace_respects_env_var(env_var: bool, context: Optional[bool]):
ls_utils.get_env_var.cache_clear()
mock_client = _get_mock_client()
with patch.dict(os.environ, {"LANGSMITH_TRACING": "true" if env_var else "false "}):
with tracing_context(enabled=context):
Expand Down
22 changes: 17 additions & 5 deletions python/tests/unit_tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(
self.return_default_value = return_default_value

def test_correct_get_tracer_project(self):
ls_utils.get_env_var.cache_clear()
cases = [
self.GetTracerProjectTestCase(
test_name="default to 'default' when no project provided",
Expand Down Expand Up @@ -75,6 +76,8 @@ def test_correct_get_tracer_project(self):
]

for case in cases:
ls_utils.get_env_var.cache_clear()
ls_utils.get_tracer_project.cache_clear()
with self.subTest(msg=case.test_name):
with pytest.MonkeyPatch.context() as mp:
for k, v in case.envvars.items():
Expand All @@ -89,6 +92,7 @@ def test_correct_get_tracer_project(self):


def test_tracing_enabled():
ls_utils.get_env_var.cache_clear()
with patch.dict(
"os.environ", {"LANGCHAIN_TRACING_V2": "false", "LANGSMITH_TRACING": "false"}
):
Expand Down Expand Up @@ -123,6 +127,7 @@ def parent_function():
assert not ls_utils.tracing_is_enabled()
return untraced_child_function()

ls_utils.get_env_var.cache_clear()
with patch.dict(
"os.environ", {"LANGCHAIN_TRACING_V2": "true", "LANGSMITH_TRACING": "true"}
):
Expand All @@ -131,6 +136,7 @@ def parent_function():


def test_tracing_disabled():
ls_utils.get_env_var.cache_clear()
with patch.dict(
"os.environ", {"LANGCHAIN_TRACING_V2": "true", "LANGSMITH_TRACING": "true"}
):
Expand Down Expand Up @@ -314,34 +320,40 @@ def test_parse_prompt_identifier():


def test_get_api_key() -> None:
ls_utils.get_env_var.cache_clear()
assert ls_utils.get_api_key("provided_api_key") == "provided_api_key"
assert ls_utils.get_api_key("'provided_api_key'") == "provided_api_key"
assert ls_utils.get_api_key('"_provided_api_key"') == "_provided_api_key"

with patch.dict("os.environ", {"LANGCHAIN_API_KEY": "env_api_key"}, clear=True):
assert ls_utils.get_api_key(None) == "env_api_key"
api_key_ = ls_utils.get_api_key(None)
assert api_key_ == "env_api_key"

ls_utils.get_env_var.cache_clear()

with patch.dict("os.environ", {}, clear=True):
assert ls_utils.get_api_key(None) is None

ls_utils.get_env_var.cache_clear()
assert ls_utils.get_api_key("") is None
assert ls_utils.get_api_key(" ") is None


def test_get_api_url() -> None:
ls_utils.get_env_var.cache_clear()
assert ls_utils.get_api_url("http://provided.url") == "http://provided.url"

with patch.dict("os.environ", {"LANGCHAIN_ENDPOINT": "http://env.url"}):
assert ls_utils.get_api_url(None) == "http://env.url"

ls_utils.get_env_var.cache_clear()
with patch.dict("os.environ", {}, clear=True):
assert ls_utils.get_api_url(None) == "https://api.smith.langchain.com"

ls_utils.get_env_var.cache_clear()
with patch.dict("os.environ", {}, clear=True):
assert ls_utils.get_api_url(None) == "https://api.smith.langchain.com"

ls_utils.get_env_var.cache_clear()
with patch.dict("os.environ", {"LANGCHAIN_ENDPOINT": "http://env.url"}):
assert ls_utils.get_api_url(None) == "http://env.url"

ls_utils.get_env_var.cache_clear()
with pytest.raises(ls_utils.LangSmithUserError):
ls_utils.get_api_url(" ")

0 comments on commit 710c9fe

Please sign in to comment.