Skip to content

Commit

Permalink
Add method to consistently get project (#289)
Browse files Browse the repository at this point in the history
We plan to introduce an environment variable in hosted langserve that
will overwrite the project used for traces from hosted deployments. We
don't centralize how we refer to projects in any of our repos, so in
order to ensure that our tracing works properly and our project
selection is consistent, we need to introduce a shared method for
getting the project that we can use throughout our different repos
  • Loading branch information
jakerachleff authored Nov 8, 2023
1 parent 661aae9 commit 94c23cd
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 11 deletions.
12 changes: 3 additions & 9 deletions python/langsmith/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,11 +661,8 @@ def create_run(
"project_name",
kwargs.pop(
"session_name",
os.environ.get(
# TODO: Deprecate LANGCHAIN_SESSION
"LANGCHAIN_PROJECT",
os.environ.get("LANGCHAIN_SESSION", "default"),
),
# if the project is not provided, use the environment's project
ls_utils.get_tracer_project(),
),
)
run_create = {
Expand Down Expand Up @@ -925,10 +922,7 @@ def get_run_url(
elif project_name is not None:
session_id = self.read_project(project_name=project_name).id
else:
project_name = os.environ.get(
"LANGCHAIN_PROJECT",
"default",
)
project_name = ls_utils.get_tracer_project()
session_id = self.read_project(project_name=project_name).id
return (
f"{self._host_url}/o/{self._get_tenant_id()}/projects/p/{_as_uuid(session_id)}/"
Expand Down
22 changes: 21 additions & 1 deletion python/langsmith/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import logging
import os
import subprocess
from typing import Any, Callable, Dict, List, Mapping, Tuple, Union
from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple, Union

import requests

Expand Down Expand Up @@ -252,6 +252,26 @@ def is_base_message_like(obj: object) -> bool:
)


def get_tracer_project(return_default_value=True) -> Optional[str]:
"""Get the project name for a LangSmith tracer."""
return os.environ.get(
# Hosted LangServe projects get precedence over all other defaults.
# This is to make sure that we always use the associated project
# for a hosted langserve deployment even if the customer sets some
# other project name in their environment.
"HOSTED_LANGSERVE_PROJECT_NAME",
os.environ.get(
"LANGCHAIN_PROJECT",
os.environ.get(
# This is the legacy name for a LANGCHAIN_PROJECT, so it
# has lower precedence than LANGCHAIN_PROJECT
"LANGCHAIN_SESSION",
"default" if return_default_value else None,
),
),
)


class FilterPoolFullWarning(logging.Filter):
"""Filter urrllib3 warnings logged when the connection pool isn't reused."""

Expand Down
32 changes: 31 additions & 1 deletion python/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ langsmith = "langsmith.cli.main:main"
python = ">=3.8.1,<4.0"
pydantic = ">=1,<3"
requests = "^2"
pytest-subtests = "^0.11.0"


[tool.poetry.group.dev.dependencies]
Expand Down
73 changes: 73 additions & 0 deletions python/tests/unit_tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import unittest

import pytest

import langsmith.utils as ls_utils


class LangSmithProjectNameTest(unittest.TestCase):
class GetTracerProjectTestCase:
def __init__(
self, test_name, envvars, expected_project_name, return_default_value=None
):
self.test_name = test_name
self.envvars = envvars
self.expected_project_name = expected_project_name
self.return_default_value = return_default_value

def test_correct_get_tracer_project(self):
cases = [
self.GetTracerProjectTestCase(
test_name="default to 'default' when no project provided",
envvars={},
expected_project_name="default",
),
self.GetTracerProjectTestCase(
test_name="default to 'default' when "
+ "return_default_value=True and no project provided",
envvars={},
expected_project_name="default",
),
self.GetTracerProjectTestCase(
test_name="do not default if return_default_value=False "
+ "when no project provided",
envvars={},
expected_project_name=None,
return_default_value=False,
),
self.GetTracerProjectTestCase(
test_name="use session_name for legacy tracers",
envvars={"LANGCHAIN_SESSION": "old_timey_session"},
expected_project_name="old_timey_session",
),
self.GetTracerProjectTestCase(
test_name="use LANGCHAIN_PROJECT over SESSION_NAME",
envvars={
"LANGCHAIN_SESSION": "old_timey_session",
"LANGCHAIN_PROJECT": "modern_session",
},
expected_project_name="modern_session",
),
self.GetTracerProjectTestCase(
test_name="hosted projects get precedence over all other defaults",
envvars={
"HOSTED_LANGSERVE_PROJECT_NAME": "hosted_project",
"LANGCHAIN_SESSION": "old_timey_session",
"LANGCHAIN_PROJECT": "modern_session",
},
expected_project_name="hosted_project",
),
]

for case in cases:
with self.subTest(msg=case.test_name):
with pytest.MonkeyPatch.context() as mp:
for k, v in case.envvars.items():
mp.setenv(k, v)

project = (
ls_utils.get_tracer_project()
if case.return_default_value is None
else ls_utils.get_tracer_project(case.return_default_value)
)
self.assertEqual(project, case.expected_project_name)

0 comments on commit 94c23cd

Please sign in to comment.