get_context()
Overview
When working with Pay-i's Python SDK, you often need to access information about the current execution context, such as which limits are being applied or what use case is being tracked. The get_context()
function provides a straightforward way to retrieve this information at runtime.
This document explains how to use get_context()
to access context information, with practical examples focused on common use cases.
What is get_context()
?
get_context()
?The get_context()
function returns the current tracking context as a PayiContext object. This context includes values from:
- Global context set in
payi_instrument()
- Context values from any active
@track
decorator - Context values from any active
track_context()
manager
from payi.lib.instrument import get_context
# Get the current context
context = get_context()
The function always returns a PayiContext object - if no context is active, it returns an empty context. This ensures your code can safely access context properties without checking for None values.
Understanding Context Sources
The context returned by get_context()
combines values from multiple sources according to the parameter precedence rules. In general:
- Values set in
payi_instrument()
provide global defaults - When contexts are nested, the innermost (latest) context's values typically take precedence for overlapping parameters
- Parameter inheritance and combination rules determine exactly how values are processed
For the specific rules about how values are inherited, overridden, or combined across different levels, refer to the Parameter Precedence in Pay-i Instrumentation documentation.
Accessing Global Context Values
When you initialize Pay-i using payi_instrument()
with configuration values, these values become part of the global context and are accessible via get_context()
:
from payi.lib.instrument import payi_instrument, get_context
# Initialize Pay-i with global context values
payi_instrument(config={
"use_case_name": "MyApplication",
"limit_ids": ["global_limit_id"],
"user_id": "default_user"
})
# Later, access these global values
context = get_context()
app_name = context.use_case_name # "MyApplication"
global_limits = context.limit_ids # ["global_limit_id"]
default_user = context.user_id # "default_user"
Key Use Cases for get_context()
get_context()
1. Checking Active Limits
One of the most valuable uses of get_context()
is retrieving the IDs of limits currently applied in your execution context. This enables you to check limit usage and adapt your application's behavior accordingly:
from payi.lib.instrument import get_context
from payi import Payi
payi_client = Payi()
def check_active_limit_usage():
"""Check the usage status of limits active in the current context."""
# Get the current context
context = get_context()
# Retrieve limit IDs from the context
active_limit_ids = context.limit_ids
if not active_limit_ids:
print("No limits are currently active in this context")
return
print(f"Active limit IDs: {active_limit_ids}")
# Check each limit's status
for limit_id in active_limit_ids:
limit = payi_client.limits.retrieve(limit_id=limit_id).limit
# Calculate usage metrics
current_usage = limit.totals.cost.total.base
max_limit = limit.max
usage_percentage = (current_usage / max_limit) * 100 if max_limit > 0 else 0
print(f"Limit '{limit.limit_name}':")
print(f" Usage: ${current_usage:.2f} of ${max_limit:.2f} ({usage_percentage:.1f}%)")
# Detect if we're approaching the limit
if usage_percentage >= 90:
print(" ⚠️ Critical: Approaching maximum")
elif usage_percentage >= limit.threshold * 100:
print(f" ⚠️ Warning: Exceeded threshold ({limit.threshold * 100:.0f}%)")
else:
print(" ✅ Within budget")
This function can be called anywhere in your application to check the status of limits active in the current context, without needing to pass limit IDs explicitly.
2. Accessing Use Case Information
When using the @track
decorator or track_context()
with use case parameters, get_context()
allows you to access the current use case information:
from payi.lib.instrument import get_context
def log_use_case_info():
"""Log information about the current use case."""
context = get_context()
if context.use_case_name:
print(f"Current use case: {context.use_case_name} (ID: {context.use_case_id}, Version: {context.use_case_version})")
if context.use_case_step:
print(f"Current step: {context.use_case_step}")
else:
print("No use case active in current context")
3. Retrieving User Attribution
When user IDs are set in the context, get_context()
lets you access this information for logging or attribution:
from payi.lib.instrument import get_context
def get_current_user():
"""Get the user ID from the current context."""
context = get_context()
return context.user_id or "anonymous"
Example: Nested Contexts
This example demonstrates how get_context()
works with nested contexts, where the innermost context's values take precedence:
from payi.lib.instrument import payi_instrument, track, track_context, get_context
# Set global defaults
payi_instrument(config={
"use_case_name": "GlobalApp",
"limit_ids": ["global_limit"],
"user_id": "default_user"
})
# Function with track decorator
@track(use_case_name="UserService")
def process_user_request():
# At this point, get_context() would return:
# - use_case_name: "UserService" (from decorator)
# - limit_ids: ["global_limit"] (from global)
# - user_id: "default_user" (from global)
context = get_context()
print("Outer context:")
print(f" use_case_name: {context.use_case_name}")
print(f" limit_ids: {context.limit_ids}")
print(f" user_id: {context.user_id}")
# Nested context with track_context
with track_context(use_case_step="login", user_id="specific_user"):
# Now get_context() would return:
# - use_case_name: "UserService" (inherited from decorator)
# - limit_ids: ["global_limit"] (inherited)
# - user_id: "specific_user" (from inner context)
# - use_case_step: "login" (from inner context)
context = get_context()
print("Inner context:")
print(f" use_case_name: {context.use_case_name}")
print(f" limit_ids: {context.limit_ids}")
print(f" user_id: {context.user_id}")
print(f" use_case_step: {context.use_case_step}")
Practical Example: Adaptive Behavior Based on Limit Status
This example demonstrates how get_context()
is used to adapt application behavior based on limit usage:
from payi.lib.instrument import get_context, track_context
from payi import Payi
from openai import OpenAI
payi_client = Payi()
openai_client = OpenAI()
def adaptive_content_generation(prompt):
"""Generate content with adaptive behavior based on current limit usage."""
# Get active limit IDs from the current context
context = get_context()
active_limit_ids = context.limit_ids or []
if not active_limit_ids:
print("No limits active in current context")
# Use default parameters when no limits are active
model = "gpt-4"
max_tokens = 500
else:
# Check if any active limit is close to its threshold
approaching_limit = False
for limit_id in active_limit_ids:
limit = payi_client.limits.retrieve(limit_id=limit_id).limit
usage_percentage = (limit.totals.cost.total.base / limit.max) * 100 if limit.max > 0 else 0
if usage_percentage >= 90:
# Very close to limit
approaching_limit = True
print(f"⚠️ Near limit '{limit.limit_name}': {usage_percentage:.1f}% used")
break
elif usage_percentage >= limit.threshold * 100:
# Above threshold but not critical
approaching_limit = True
print(f"⚠️ Approaching limit '{limit.limit_name}': {usage_percentage:.1f}% used")
break
# Adjust parameters based on limit status
if approaching_limit:
# Use more economical settings when approaching limits
model = "gpt-3.5-turbo"
max_tokens = 250
print(f"Using economical settings: {model} with {max_tokens} max tokens")
else:
# Use standard settings when well within limits
model = "gpt-4"
max_tokens = 500
print(f"Using standard settings: {model} with {max_tokens} max tokens")
# Generate content with the selected parameters
response = openai_client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
max_tokens=max_tokens
)
return response.choices[0].message.content
PayiContext Properties
The PayiContext object returned by get_context()
can contain these properties (all are optional):
Property | Type | Description |
---|---|---|
use_case_name | string | Name of the current use case |
use_case_id | string | Unique ID of the current use case |
use_case_version | integer | Version of the current use case |
use_case_step | string | Current step in the use case flow |
limit_ids | list of strings | IDs of limits being applied |
user_id | string | ID of the current user |
request_tags | list of strings | Tags associated with the request |
price_as_category | string | Category for pricing |
price_as_resource | string | Resource for pricing |
resource_scope | string | Scope for resource pricing |
proxy | boolean | Flag for proxy mode |
last_result | object | Contains information about the last API call (if available) |
Best Practices
1. Use Direct Property Access
Since get_context()
always returns a PayiContext object, you can directly access properties without defensive coding:
# Always safe - properties will be None if not set
context = get_context()
user_id = context.user_id
limit_ids = context.limit_ids
2. Provide Default Values for Optional Properties
When you need a default value for a property that might be None, use the or
operator:
# Use default values for properties that might be None
context = get_context()
user_id = context.user_id or "anonymous"
limit_ids = context.limit_ids or []
3. Treat Context as Read-Only
The context object returned by get_context()
should be treated as read-only:
# Don't do this - modifying the returned context doesn't affect the actual context
context = get_context()
context.user_id = "new_user" # This won't change the actual context
# Instead, use track_context to set new values
with track_context(user_id="new_user"):
# Now the context has the new user_id
4. Use Context for Runtime Decisions
The primary value of get_context()
is for making runtime decisions based on the current execution context:
def select_appropriate_model():
"""Select the appropriate model based on the current context."""
context = get_context()
# Check if this is a premium use case
use_case = context.use_case_name or ""
if "premium" in use_case.lower():
return "gpt-4"
# Check if we're in a high-priority flow
if context.use_case_step in ["critical", "high_priority"]:
return "gpt-4"
# Default to more economical model
return "gpt-3.5-turbo"
Related Functions
Context Management Functions
While get_context()
is used to access context values, these functions are used to create and manage contexts:
payi_instrument()
- Initializes the SDK and establishes the global context@track
- Function decorator that creates a context for the decorated functiontrack_context()
- Context manager that creates a context for a block of code
For details on how context values are inherited, combined, or overridden across different levels, see Parameter Precedence in Pay-i Instrumentation.
Summary
The get_context()
function provides read-only access to the current execution context in Pay-i's instrumentation system. It always returns a PayiContext object, which contains information from global configuration, active decorators, and active context managers, combined according to Pay-i's parameter precedence rules.
By retrieving this context information, you can build more responsive applications that adapt to different scenarios while maintaining clean, modular code.
These functions are particularly valuable for:
- Checking limit usage without passing limit IDs explicitly
- Adapting behavior based on context properties
- Retrieving use case and user information for logging
- Building context-aware utility functions
Updated 1 day ago