From a19056ad6d986fc318f69d8da0b429f14aea161b Mon Sep 17 00:00:00 2001 From: Nimar Date: Tue, 16 Sep 2025 11:16:50 +0200 Subject: [PATCH 1/2] fix(get_client): preserve properties on client such as environment --- langfuse/_client/get_client.py | 2 + langfuse/_client/resource_manager.py | 1 + tests/test_resource_manager.py | 77 ++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 tests/test_resource_manager.py diff --git a/langfuse/_client/get_client.py b/langfuse/_client/get_client.py index ff619095e..141d5336c 100644 --- a/langfuse/_client/get_client.py +++ b/langfuse/_client/get_client.py @@ -98,6 +98,7 @@ def get_client(*, public_key: Optional[str] = None) -> Langfuse: secret_key=instance.secret_key, host=instance.host, tracing_enabled=instance.tracing_enabled, + environment=instance.environment, ) else: @@ -131,4 +132,5 @@ def get_client(*, public_key: Optional[str] = None) -> Langfuse: secret_key=target_instance.secret_key, host=target_instance.host, tracing_enabled=target_instance.tracing_enabled, + environment=target_instance.environment, ) diff --git a/langfuse/_client/resource_manager.py b/langfuse/_client/resource_manager.py index e0e3cbadc..afd335131 100644 --- a/langfuse/_client/resource_manager.py +++ b/langfuse/_client/resource_manager.py @@ -162,6 +162,7 @@ def _initialize_instance( self.tracing_enabled = tracing_enabled self.host = host self.mask = mask + self.environment = environment # OTEL Tracer if tracing_enabled: diff --git a/tests/test_resource_manager.py b/tests/test_resource_manager.py new file mode 100644 index 000000000..c35f86ded --- /dev/null +++ b/tests/test_resource_manager.py @@ -0,0 +1,77 @@ +"""Test environment setting on Langfuse get_client() function.""" + +import pytest +from langfuse import Langfuse +from langfuse._client.get_client import get_client + + +def test_get_client_preserves_environment(): + """Test that get_client() preserves the environment when returning existing clients.""" + test_env = "production-test-env" + original_client = Langfuse(environment=test_env) + + # Verify the original client has the correct environment + assert original_client._environment == test_env, ( + f"original client environment should be '{test_env}', got '{original_client._environment}'" + ) + + # call get_client() should return a client with the same environment + retrieved_client = get_client() + + assert retrieved_client._environment == test_env, ( + f"get_client() should return client with environment '{test_env}', got '{retrieved_client._environment}'" + ) + + original_client.shutdown() + + +def test_get_client_with_multiple_environments(): + """Test get_client() behavior with multiple clients having different environments.""" + env_a = "environment-a" + env_b = "environment-b" + + client_a = Langfuse(public_key="pk-a", secret_key="sk-a", environment=env_a) + client_b = Langfuse(public_key="pk-b", secret_key="sk-b", environment=env_b) + + # original clients should have correct environments + assert client_a._environment == env_a + assert client_b._environment == env_b + + # Get clients using get_client() with specific public keys + retrieved_a = get_client(public_key="pk-a") + retrieved_b = get_client(public_key="pk-b") + + # should have the same environments as the originals + assert retrieved_a._environment == env_a, ( + f"Expected client A environment to be '{env_a}', got '{retrieved_a._environment}'" + ) + assert retrieved_b._environment == env_b, ( + f"Expected client B environment to be '{env_b}', got '{retrieved_b._environment}'" + ) + + client_a.shutdown() + client_b.shutdown() + + +def test_get_client_single_client_environment(): + """Test that get_client() preserves environment in single-client scenario.""" + # Clean state - ensure no existing clients + from langfuse._client.resource_manager import LangfuseResourceManager + + with LangfuseResourceManager._lock: + LangfuseResourceManager._instances.clear() + + test_env = "single-client-env" + + client = Langfuse(environment=test_env) + assert client._environment == test_env + + # get_client() should return a client with the same environment + retrieved = get_client() + + # This assertion demonstrates the bug + assert retrieved._environment == test_env, ( + f"Expected single client scenario to preserve environment '{test_env}', got '{retrieved._environment}'" + ) + + client.shutdown() From 7dd8c5e4b5d49b62606c21b1c86a3dc2923c8904 Mon Sep 17 00:00:00 2001 From: Nimar Date: Tue, 16 Sep 2025 11:41:24 +0200 Subject: [PATCH 2/2] also preserve the other properties --- langfuse/_client/get_client.py | 38 +++++--- langfuse/_client/resource_manager.py | 10 +++ tests/test_resource_manager.py | 124 ++++++++++++++------------- 3 files changed, 97 insertions(+), 75 deletions(-) diff --git a/langfuse/_client/get_client.py b/langfuse/_client/get_client.py index 141d5336c..8bcdecd40 100644 --- a/langfuse/_client/get_client.py +++ b/langfuse/_client/get_client.py @@ -33,6 +33,28 @@ def _set_current_public_key(public_key: Optional[str]) -> Iterator[None]: _current_public_key.reset(token) +def _create_client_from_instance( + instance: "LangfuseResourceManager", public_key: Optional[str] = None +) -> Langfuse: + """Create a Langfuse client from a resource manager instance with all settings preserved.""" + return Langfuse( + public_key=public_key or instance.public_key, + secret_key=instance.secret_key, + host=instance.host, + tracing_enabled=instance.tracing_enabled, + environment=instance.environment, + timeout=instance.timeout, + flush_at=instance.flush_at, + flush_interval=instance.flush_interval, + release=instance.release, + media_upload_thread_count=instance.media_upload_thread_count, + sample_rate=instance.sample_rate, + mask=instance.mask, + blocked_instrumentation_scopes=instance.blocked_instrumentation_scopes, + additional_headers=instance.additional_headers, + ) + + def get_client(*, public_key: Optional[str] = None) -> Langfuse: """Get or create a Langfuse client instance. @@ -93,13 +115,7 @@ def get_client(*, public_key: Optional[str] = None) -> Langfuse: # Initialize with the credentials bound to the instance # This is important if the original instance was instantiated # via constructor arguments - return Langfuse( - public_key=instance.public_key, - secret_key=instance.secret_key, - host=instance.host, - tracing_enabled=instance.tracing_enabled, - environment=instance.environment, - ) + return _create_client_from_instance(instance) else: # Multiple clients exist but no key specified - disable tracing @@ -127,10 +143,4 @@ def get_client(*, public_key: Optional[str] = None) -> Langfuse: ) # target_instance is guaranteed to be not None at this point - return Langfuse( - public_key=public_key, - secret_key=target_instance.secret_key, - host=target_instance.host, - tracing_enabled=target_instance.tracing_enabled, - environment=target_instance.environment, - ) + return _create_client_from_instance(target_instance, public_key) diff --git a/langfuse/_client/resource_manager.py b/langfuse/_client/resource_manager.py index afd335131..70ed5b17c 100644 --- a/langfuse/_client/resource_manager.py +++ b/langfuse/_client/resource_manager.py @@ -164,6 +164,16 @@ def _initialize_instance( self.mask = mask self.environment = environment + # Store additional client settings for get_client() to use + self.timeout = timeout + self.flush_at = flush_at + self.flush_interval = flush_interval + self.release = release + self.media_upload_thread_count = media_upload_thread_count + self.sample_rate = sample_rate + self.blocked_instrumentation_scopes = blocked_instrumentation_scopes + self.additional_headers = additional_headers + # OTEL Tracer if tracing_enabled: tracer_provider = tracer_provider or _init_tracer_provider( diff --git a/tests/test_resource_manager.py b/tests/test_resource_manager.py index c35f86ded..fa6eb56bf 100644 --- a/tests/test_resource_manager.py +++ b/tests/test_resource_manager.py @@ -1,77 +1,79 @@ -"""Test environment setting on Langfuse get_client() function.""" +"""Test the LangfuseResourceManager and get_client() function.""" -import pytest from langfuse import Langfuse from langfuse._client.get_client import get_client +from langfuse._client.resource_manager import LangfuseResourceManager -def test_get_client_preserves_environment(): - """Test that get_client() preserves the environment when returning existing clients.""" - test_env = "production-test-env" - original_client = Langfuse(environment=test_env) +def test_get_client_preserves_all_settings(): + """Test that get_client() preserves environment and all client settings.""" + with LangfuseResourceManager._lock: + LangfuseResourceManager._instances.clear() - # Verify the original client has the correct environment - assert original_client._environment == test_env, ( - f"original client environment should be '{test_env}', got '{original_client._environment}'" - ) + settings = { + "environment": "test-env", + "release": "v1.2.3", + "timeout": 30, + "flush_at": 100, + "sample_rate": 0.8, + "additional_headers": {"X-Custom": "value"}, + } - # call get_client() should return a client with the same environment + original_client = Langfuse(**settings) retrieved_client = get_client() - assert retrieved_client._environment == test_env, ( - f"get_client() should return client with environment '{test_env}', got '{retrieved_client._environment}'" - ) - - original_client.shutdown() - + assert retrieved_client._environment == settings["environment"] -def test_get_client_with_multiple_environments(): - """Test get_client() behavior with multiple clients having different environments.""" - env_a = "environment-a" - env_b = "environment-b" + assert retrieved_client._resources is not None + rm = retrieved_client._resources + assert rm.environment == settings["environment"] + assert rm.timeout == settings["timeout"] + assert rm.sample_rate == settings["sample_rate"] + assert rm.additional_headers == settings["additional_headers"] - client_a = Langfuse(public_key="pk-a", secret_key="sk-a", environment=env_a) - client_b = Langfuse(public_key="pk-b", secret_key="sk-b", environment=env_b) - - # original clients should have correct environments - assert client_a._environment == env_a - assert client_b._environment == env_b + original_client.shutdown() - # Get clients using get_client() with specific public keys - retrieved_a = get_client(public_key="pk-a") - retrieved_b = get_client(public_key="pk-b") - # should have the same environments as the originals - assert retrieved_a._environment == env_a, ( - f"Expected client A environment to be '{env_a}', got '{retrieved_a._environment}'" - ) - assert retrieved_b._environment == env_b, ( - f"Expected client B environment to be '{env_b}', got '{retrieved_b._environment}'" - ) +def test_get_client_multiple_clients_preserve_different_settings(): + """Test that get_client() preserves different settings for multiple clients.""" + # Settings for client A + settings_a = { + "public_key": "pk-comprehensive-a", + "secret_key": "sk-comprehensive-a", + "environment": "env-a", + "release": "release-a", + "timeout": 10, + "sample_rate": 0.5, + } + + # Settings for client B + settings_b = { + "public_key": "pk-comprehensive-b", + "secret_key": "sk-comprehensive-b", + "environment": "env-b", + "release": "release-b", + "timeout": 20, + "sample_rate": 0.9, + } + + client_a = Langfuse(**settings_a) + client_b = Langfuse(**settings_b) + + # Get clients via get_client() + retrieved_a = get_client(public_key="pk-comprehensive-a") + retrieved_b = get_client(public_key="pk-comprehensive-b") + + # Verify each client preserves its own settings + assert retrieved_a._environment == settings_a["environment"] + assert retrieved_b._environment == settings_b["environment"] + + if retrieved_a._resources and retrieved_b._resources: + assert retrieved_a._resources.timeout == settings_a["timeout"] + assert retrieved_b._resources.timeout == settings_b["timeout"] + assert retrieved_a._resources.sample_rate == settings_a["sample_rate"] + assert retrieved_b._resources.sample_rate == settings_b["sample_rate"] + assert retrieved_a._resources.release == settings_a["release"] + assert retrieved_b._resources.release == settings_b["release"] client_a.shutdown() client_b.shutdown() - - -def test_get_client_single_client_environment(): - """Test that get_client() preserves environment in single-client scenario.""" - # Clean state - ensure no existing clients - from langfuse._client.resource_manager import LangfuseResourceManager - - with LangfuseResourceManager._lock: - LangfuseResourceManager._instances.clear() - - test_env = "single-client-env" - - client = Langfuse(environment=test_env) - assert client._environment == test_env - - # get_client() should return a client with the same environment - retrieved = get_client() - - # This assertion demonstrates the bug - assert retrieved._environment == test_env, ( - f"Expected single client scenario to preserve environment '{test_env}', got '{retrieved._environment}'" - ) - - client.shutdown()