langfun 0.1.2.dev202509250804__tar.gz → 0.1.2.dev202509260805__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/PKG-INFO +1 -1
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/__init__.py +4 -5
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/base_environment.py +41 -34
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/base_feature.py +10 -1
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/base_sandbox.py +27 -26
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/base_test.py +106 -33
- langfun-0.1.2.dev202509260805/langfun/env/event_handlers/__init__.py +12 -0
- langfun-0.1.2.dev202509260805/langfun/env/event_handlers/base.py +271 -0
- langfun-0.1.2.dev202509260805/langfun/env/event_handlers/event_logger.py +415 -0
- langfun-0.1.2.dev202509260805/langfun/env/event_handlers/event_logger_test.py +289 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/interface.py +103 -380
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/interface_test.py +3 -3
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/load_balancers_test.py +3 -15
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/test_utils.py +12 -26
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun.egg-info/PKG-INFO +1 -1
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun.egg-info/SOURCES.txt +5 -1
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/LICENSE +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/README.md +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/assistant/capabilities/gui/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/assistant/capabilities/gui/bounding_box_parser.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/assistant/capabilities/gui/bounding_box_parser_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/assistant/capabilities/gui/drawing.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/assistant/capabilities/gui/drawing_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/assistant/capabilities/gui/location.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/assistant/capabilities/gui/location_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/agentic/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/agentic/action.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/agentic/action_eval.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/agentic/action_eval_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/agentic/action_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/async_support.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/async_support_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/correction.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/correction_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/execution.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/execution_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/generation.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/generation_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/parsing.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/parsing_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/sandboxing.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/coding/python/sandboxing_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/component.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/component_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/concurrent.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/concurrent_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/console.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/console_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/data/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/data/conversion/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/data/conversion/anthropic.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/data/conversion/anthropic_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/data/conversion/gemini.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/data/conversion/gemini_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/data/conversion/openai.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/data/conversion/openai_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/base.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/base_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/matching.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/matching_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/patching.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/patching_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/scoring.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/scoring_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/checkpointing.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/checkpointing_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/eval_test_helper.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/evaluation.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/evaluation_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/example.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/example_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/experiment.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/experiment_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/metric_values.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/metric_values_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/metrics.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/metrics_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/progress.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/progress_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/progress_tracking.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/progress_tracking_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/reporting.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/reporting_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/runners.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/eval/v2/runners_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/langfunc.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/langfunc_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/language_model.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/language_model_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/anthropic.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/anthropic_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/azure_openai.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/azure_openai_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/cache/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/cache/base.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/cache/in_memory.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/cache/in_memory_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/compositional.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/compositional_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/deepseek.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/deepseek_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/fake.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/fake_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/gemini.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/gemini_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/google_genai.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/google_genai_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/groq.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/groq_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/llama_cpp.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/llama_cpp_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/openai.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/openai_compatible.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/openai_compatible_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/openai_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/rest.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/rest_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/vertexai.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/llms/vertexai_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/logging.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/logging_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/memories/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/memories/conversation_history.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/memories/conversation_history_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/memory.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/message.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/message_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/audio.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/audio_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/image.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/image_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/mime.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/mime_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/pdf.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/pdf_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/video.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modalities/video_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modality.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/modality_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/natural_language.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/natural_language_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/sampling.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/sampling_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/completion.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/completion_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/description.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/description_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/function_generation.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/function_generation_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/mapping.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/mapping_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/parsing.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/parsing_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/querying.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/querying_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/schema.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/schema_generation.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/schema_generation_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/schema_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/scoring.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/scoring_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/tokenization.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/structured/tokenization_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/subscription.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/subscription_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/template.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/template_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/__init__.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/completion.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/completion_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/conversation.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/conversation_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/demonstration.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/demonstration_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/selfplay.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/core/templates/selfplay_test.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/load_balancers.py +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun.egg-info/dependency_links.txt +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun.egg-info/requires.txt +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun.egg-info/top_level.txt +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/setup.cfg +0 -0
- {langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/setup.py +0 -0
|
@@ -13,16 +13,12 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
"""Environment for LLM agents."""
|
|
15
15
|
|
|
16
|
-
# pylint: disable=g-importing-member, g-bad-import-order
|
|
17
|
-
from langfun.env.interface import EnvironmentId
|
|
18
|
-
from langfun.env.interface import SandboxId
|
|
19
|
-
|
|
16
|
+
# pylint: disable=g-importing-member, g-bad-import-order, g-import-not-at-top
|
|
20
17
|
from langfun.env.interface import EnvironmentError # pylint: disable=redefined-builtin
|
|
21
18
|
from langfun.env.interface import EnvironmentOutageError
|
|
22
19
|
from langfun.env.interface import EnvironmentOverloadError
|
|
23
20
|
from langfun.env.interface import SandboxError
|
|
24
21
|
from langfun.env.interface import SandboxStateError
|
|
25
|
-
from langfun.env.interface import EnvironmentEventHandler
|
|
26
22
|
|
|
27
23
|
from langfun.env.interface import Environment
|
|
28
24
|
from langfun.env.interface import Sandbox
|
|
@@ -35,4 +31,7 @@ from langfun.env.base_feature import BaseFeature
|
|
|
35
31
|
from langfun.env import load_balancers
|
|
36
32
|
from langfun.env.load_balancers import LoadBalancer
|
|
37
33
|
|
|
34
|
+
from langfun.env import event_handlers
|
|
35
|
+
EventHandler = event_handlers.EventHandler
|
|
36
|
+
|
|
38
37
|
# Google-internal imports.
|
{langfun-0.1.2.dev202509250804 → langfun-0.1.2.dev202509260805}/langfun/env/base_environment.py
RENAMED
|
@@ -34,6 +34,7 @@ import langfun.core as lf
|
|
|
34
34
|
from langfun.env import base_sandbox
|
|
35
35
|
from langfun.env import interface
|
|
36
36
|
from langfun.env import load_balancers
|
|
37
|
+
from langfun.env.event_handlers import base as event_handler_base
|
|
37
38
|
import pyglove as pg
|
|
38
39
|
|
|
39
40
|
|
|
@@ -65,10 +66,20 @@ class BaseEnvironment(interface.Environment):
|
|
|
65
66
|
load_balancer: Annotated[
|
|
66
67
|
load_balancers.LoadBalancer,
|
|
67
68
|
(
|
|
68
|
-
'The load balancer for the environment.'
|
|
69
|
+
'The load balancer for the environment to acquire sandboxes.'
|
|
69
70
|
)
|
|
70
71
|
] = load_balancers.RoundRobin()
|
|
71
72
|
|
|
73
|
+
sandbox_keepalive_interval: Annotated[
|
|
74
|
+
float | None,
|
|
75
|
+
(
|
|
76
|
+
'The interval in seconds to send keepalive pings to sandboxes. '
|
|
77
|
+
'If None, sandbox keepalive is disabled. Please note that sandbox '
|
|
78
|
+
'keepalive is different from feature housekeeping. Usually sandbox '
|
|
79
|
+
'keepalive and feature housekeeping are different operations.'
|
|
80
|
+
)
|
|
81
|
+
] = None
|
|
82
|
+
|
|
72
83
|
proactive_session_setup: Annotated[
|
|
73
84
|
bool,
|
|
74
85
|
(
|
|
@@ -79,6 +90,13 @@ class BaseEnvironment(interface.Environment):
|
|
|
79
90
|
)
|
|
80
91
|
] = True
|
|
81
92
|
|
|
93
|
+
event_handlers: Annotated[
|
|
94
|
+
list[event_handler_base.EventHandler],
|
|
95
|
+
(
|
|
96
|
+
'User handler for the environment events.'
|
|
97
|
+
)
|
|
98
|
+
] = []
|
|
99
|
+
|
|
82
100
|
outage_grace_period: Annotated[
|
|
83
101
|
float,
|
|
84
102
|
(
|
|
@@ -97,13 +115,15 @@ class BaseEnvironment(interface.Environment):
|
|
|
97
115
|
)
|
|
98
116
|
] = 10.0
|
|
99
117
|
|
|
100
|
-
|
|
118
|
+
housekeep_interval: Annotated[
|
|
101
119
|
float,
|
|
102
120
|
(
|
|
103
|
-
'The interval in seconds for
|
|
104
|
-
'
|
|
121
|
+
'The interval in seconds for environment housekeeping. It recycles '
|
|
122
|
+
'the dead sandboxes in the pool. This interval is the minimal time '
|
|
123
|
+
'to detect outage while there is no request to obtain new sandboxes.'
|
|
124
|
+
'This is applicable only when the environment enables pooling.'
|
|
105
125
|
)
|
|
106
|
-
] =
|
|
126
|
+
] = 10.0
|
|
107
127
|
|
|
108
128
|
pool_operation_max_parallelism: Annotated[
|
|
109
129
|
int,
|
|
@@ -145,6 +165,7 @@ class BaseEnvironment(interface.Environment):
|
|
|
145
165
|
sandbox_id: str,
|
|
146
166
|
reusable: bool,
|
|
147
167
|
proactive_session_setup: bool,
|
|
168
|
+
keepalive_interval: float | None,
|
|
148
169
|
) -> base_sandbox.BaseSandbox:
|
|
149
170
|
"""Creates a sandbox with the given identifier.
|
|
150
171
|
|
|
@@ -153,6 +174,8 @@ class BaseEnvironment(interface.Environment):
|
|
|
153
174
|
reusable: Whether the sandbox is reusable across user sessions.
|
|
154
175
|
proactive_session_setup: Whether the sandbox performs session setup work
|
|
155
176
|
before a user session is started.
|
|
177
|
+
keepalive_interval: Interval to ping the sandbox for keeping it alive.
|
|
178
|
+
If None, the sandbox will not be pinged.
|
|
156
179
|
|
|
157
180
|
Returns:
|
|
158
181
|
The created sandbox.
|
|
@@ -194,6 +217,7 @@ class BaseEnvironment(interface.Environment):
|
|
|
194
217
|
def _start(self) -> None:
|
|
195
218
|
"""Implementation of starting the environment."""
|
|
196
219
|
if self.min_pool_size > 0:
|
|
220
|
+
# Pre-allocate the sandbox pool before usage.
|
|
197
221
|
self._sandbox_pool = [None] * self.min_pool_size
|
|
198
222
|
for i, sandbox, _ in lf.concurrent_map(
|
|
199
223
|
lambda i: self._bring_up_sandbox_with_retry(
|
|
@@ -207,12 +231,15 @@ class BaseEnvironment(interface.Environment):
|
|
|
207
231
|
),
|
|
208
232
|
):
|
|
209
233
|
self._sandbox_pool[i] = sandbox
|
|
234
|
+
|
|
210
235
|
self._next_sandbox_id = len(self._sandbox_pool)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
236
|
+
|
|
237
|
+
if self.enable_pooling:
|
|
238
|
+
self._housekeep_thread = threading.Thread(
|
|
239
|
+
target=self._housekeep_loop, daemon=True
|
|
240
|
+
)
|
|
241
|
+
self._housekeep_counter = 0
|
|
242
|
+
self._housekeep_thread.start()
|
|
216
243
|
|
|
217
244
|
def _shutdown(self) -> None:
|
|
218
245
|
"""Implementation of shutting down the environment."""
|
|
@@ -256,7 +283,7 @@ class BaseEnvironment(interface.Environment):
|
|
|
256
283
|
@property
|
|
257
284
|
def enable_pooling(self) -> bool:
|
|
258
285
|
"""Returns whether the environment enables pooling."""
|
|
259
|
-
return self.
|
|
286
|
+
return self.max_pool_size > 0
|
|
260
287
|
|
|
261
288
|
@property
|
|
262
289
|
def status(self) -> interface.Environment.Status:
|
|
@@ -314,11 +341,6 @@ class BaseEnvironment(interface.Environment):
|
|
|
314
341
|
self._start_time = time.time()
|
|
315
342
|
self._set_status(self.Status.ONLINE)
|
|
316
343
|
self.on_start(duration=time.time() - starting_time)
|
|
317
|
-
|
|
318
|
-
pg.logging.info(
|
|
319
|
-
'[%s]: %s started in %.2f seconds.',
|
|
320
|
-
self.id, self.__class__.__name__, time.time() - starting_time
|
|
321
|
-
)
|
|
322
344
|
except BaseException as e:
|
|
323
345
|
self.on_start(duration=time.time() - starting_time, error=e)
|
|
324
346
|
self.shutdown()
|
|
@@ -338,13 +360,8 @@ class BaseEnvironment(interface.Environment):
|
|
|
338
360
|
self._set_status(self.Status.SHUTTING_DOWN)
|
|
339
361
|
|
|
340
362
|
try:
|
|
341
|
-
|
|
342
|
-
self._shutdown()
|
|
363
|
+
self._shutdown()
|
|
343
364
|
self.on_shutdown()
|
|
344
|
-
pg.logging.info(
|
|
345
|
-
'[%s]: %s shutdown in %.2f seconds.',
|
|
346
|
-
self.id, self.__class__.__name__, t.elapse
|
|
347
|
-
)
|
|
348
365
|
except BaseException as e: # pylint: disable=broad-except
|
|
349
366
|
self.on_shutdown(error=e)
|
|
350
367
|
raise e
|
|
@@ -416,6 +433,7 @@ class BaseEnvironment(interface.Environment):
|
|
|
416
433
|
sandbox_id=sandbox_id,
|
|
417
434
|
reusable=self.enable_pooling,
|
|
418
435
|
proactive_session_setup=self.proactive_session_setup,
|
|
436
|
+
keepalive_interval=self.sandbox_keepalive_interval,
|
|
419
437
|
)
|
|
420
438
|
for handler in self.event_handlers:
|
|
421
439
|
sandbox.add_event_handler(handler)
|
|
@@ -482,19 +500,8 @@ class BaseEnvironment(interface.Environment):
|
|
|
482
500
|
|
|
483
501
|
def _housekeep_loop(self) -> None:
|
|
484
502
|
"""Housekeeping loop for the environment."""
|
|
485
|
-
pg.logging.info(
|
|
486
|
-
'[%s]: %s maintenance thread started.', self.id, self.__class__.__name__
|
|
487
|
-
)
|
|
488
|
-
stats_report_time = time.time()
|
|
489
503
|
while self._status not in (self.Status.SHUTTING_DOWN, self.Status.OFFLINE):
|
|
490
504
|
housekeep_start_time = time.time()
|
|
491
|
-
if time.time() - stats_report_time > self.stats_report_interval:
|
|
492
|
-
pg.logging.info(
|
|
493
|
-
'[%s] %s stats: %s.',
|
|
494
|
-
self.id, self.__class__.__name__, self.stats()
|
|
495
|
-
)
|
|
496
|
-
stats_report_time = time.time()
|
|
497
|
-
|
|
498
505
|
dead_pool_indices = [
|
|
499
506
|
i for i, s in enumerate(self._sandbox_pool)
|
|
500
507
|
if s.status == interface.Sandbox.Status.OFFLINE
|
|
@@ -514,7 +521,7 @@ class BaseEnvironment(interface.Environment):
|
|
|
514
521
|
break
|
|
515
522
|
self._housekeep_counter += 1
|
|
516
523
|
self.on_housekeep(time.time() - housekeep_start_time)
|
|
517
|
-
time.sleep(
|
|
524
|
+
time.sleep(self.housekeep_interval)
|
|
518
525
|
|
|
519
526
|
def _replace_dead_sandboxes(self, dead_pool_indices: list[int]) -> bool:
|
|
520
527
|
"""Replaces a dead sandbox with a new one.
|
|
@@ -23,6 +23,7 @@ the `Environment` and `Sandbox` interfaces directly.
|
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
import functools
|
|
26
|
+
import os
|
|
26
27
|
import time
|
|
27
28
|
from typing import Annotated, Callable
|
|
28
29
|
|
|
@@ -106,6 +107,14 @@ class BaseFeature(interface.Feature):
|
|
|
106
107
|
assert self._sandbox is not None, 'Feature has not been set up yet.'
|
|
107
108
|
return self._sandbox
|
|
108
109
|
|
|
110
|
+
@property
|
|
111
|
+
def working_dir(self) -> str | None:
|
|
112
|
+
"""Returns the working directory of the feature."""
|
|
113
|
+
sandbox_workdir = self.sandbox.working_dir
|
|
114
|
+
if sandbox_workdir is None:
|
|
115
|
+
return None
|
|
116
|
+
return os.path.join(sandbox_workdir, self.name)
|
|
117
|
+
|
|
109
118
|
#
|
|
110
119
|
# Setup and teardown of the feature.
|
|
111
120
|
#
|
|
@@ -204,7 +213,7 @@ class BaseFeature(interface.Feature):
|
|
|
204
213
|
self,
|
|
205
214
|
name: str,
|
|
206
215
|
duration: float,
|
|
207
|
-
error: BaseException | None,
|
|
216
|
+
error: BaseException | None = None,
|
|
208
217
|
**kwargs
|
|
209
218
|
) -> None:
|
|
210
219
|
"""Called when a sandbox activity is performed."""
|
|
@@ -29,6 +29,7 @@ import time
|
|
|
29
29
|
from typing import Annotated, Any, Callable, Iterator, Sequence, Type
|
|
30
30
|
|
|
31
31
|
from langfun.env import interface
|
|
32
|
+
from langfun.env.event_handlers import base as event_handler_base
|
|
32
33
|
import pyglove as pg
|
|
33
34
|
|
|
34
35
|
|
|
@@ -36,7 +37,7 @@ class BaseSandbox(interface.Sandbox):
|
|
|
36
37
|
"""Base class for a sandbox."""
|
|
37
38
|
|
|
38
39
|
id: Annotated[
|
|
39
|
-
interface.
|
|
40
|
+
interface.Sandbox.Id,
|
|
40
41
|
'The identifier for the sandbox.'
|
|
41
42
|
]
|
|
42
43
|
|
|
@@ -242,14 +243,14 @@ class BaseSandbox(interface.Sandbox):
|
|
|
242
243
|
|
|
243
244
|
def add_event_handler(
|
|
244
245
|
self,
|
|
245
|
-
event_handler:
|
|
246
|
+
event_handler: event_handler_base.EventHandler | None
|
|
246
247
|
) -> None:
|
|
247
248
|
"""Sets the event handler for the sandbox."""
|
|
248
249
|
self._event_handlers.append(event_handler)
|
|
249
250
|
|
|
250
251
|
def remove_event_handler(
|
|
251
252
|
self,
|
|
252
|
-
event_handler:
|
|
253
|
+
event_handler: event_handler_base.EventHandler | None
|
|
253
254
|
) -> None:
|
|
254
255
|
"""Removes the event handler for the sandbox."""
|
|
255
256
|
self._event_handlers.remove(event_handler)
|
|
@@ -357,10 +358,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
357
358
|
|
|
358
359
|
duration = time.time() - starting_time
|
|
359
360
|
self.on_start(duration)
|
|
360
|
-
pg.logging.info(
|
|
361
|
-
'[%s]: Sandbox started in %.2f seconds.',
|
|
362
|
-
self.id, duration
|
|
363
|
-
)
|
|
364
361
|
except BaseException as e: # pylint: disable=broad-except
|
|
365
362
|
duration = time.time() - starting_time
|
|
366
363
|
pg.logging.error(
|
|
@@ -422,7 +419,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
422
419
|
return
|
|
423
420
|
|
|
424
421
|
self._set_status(interface.Sandbox.Status.SHUTTING_DOWN)
|
|
425
|
-
shutdown_start_time = time.time()
|
|
426
422
|
|
|
427
423
|
if (self._housekeep_thread is not None
|
|
428
424
|
and threading.current_thread() is not self._housekeep_thread):
|
|
@@ -433,15 +429,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
433
429
|
try:
|
|
434
430
|
self._shutdown()
|
|
435
431
|
self._set_status(interface.Sandbox.Status.OFFLINE)
|
|
436
|
-
|
|
437
|
-
pg.logging.info(
|
|
438
|
-
'[%s]: Sandbox shutdown in %.2f seconds. '
|
|
439
|
-
'(lifetime: %.2f seconds, teardown errors: %s)',
|
|
440
|
-
self.id,
|
|
441
|
-
time.time() - shutdown_start_time,
|
|
442
|
-
time.time() - self._start_time if self._start_time else 0,
|
|
443
|
-
teardown_error
|
|
444
|
-
)
|
|
445
432
|
self.on_shutdown(teardown_error)
|
|
446
433
|
shutdown_error = None
|
|
447
434
|
except BaseException as e: # pylint: disable=broad-except
|
|
@@ -656,14 +643,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
656
643
|
self._set_status(interface.Sandbox.Status.ACQUIRED)
|
|
657
644
|
shutdown_sandbox = True
|
|
658
645
|
|
|
659
|
-
pg.logging.info(
|
|
660
|
-
'[%s]: User session %s ended. '
|
|
661
|
-
'(lifetime: %.2f seconds, teardown errors: %s).',
|
|
662
|
-
self.id,
|
|
663
|
-
self._session_id,
|
|
664
|
-
time.time() - self._session_start_time,
|
|
665
|
-
end_session_error
|
|
666
|
-
)
|
|
667
646
|
self._session_start_time = None
|
|
668
647
|
self._session_event_handler = None
|
|
669
648
|
|
|
@@ -687,9 +666,31 @@ class BaseSandbox(interface.Sandbox):
|
|
|
687
666
|
last_ping = now
|
|
688
667
|
last_housekeep_time = {name: now for name in self._features.keys()}
|
|
689
668
|
|
|
669
|
+
def _next_housekeep_wait_time() -> float:
|
|
670
|
+
# Decide how long to sleep for the next housekeeping.
|
|
671
|
+
next_housekeep_time = None
|
|
672
|
+
if self.keepalive_interval is not None:
|
|
673
|
+
next_housekeep_time = last_ping + self.keepalive_interval
|
|
674
|
+
|
|
675
|
+
for name, feature in self._features.items():
|
|
676
|
+
if feature.housekeep_interval is None:
|
|
677
|
+
continue
|
|
678
|
+
next_feature_housekeep_time = (
|
|
679
|
+
last_housekeep_time[name] + feature.housekeep_interval
|
|
680
|
+
)
|
|
681
|
+
if (next_housekeep_time is None
|
|
682
|
+
or next_housekeep_time > next_feature_housekeep_time):
|
|
683
|
+
next_housekeep_time = next_feature_housekeep_time
|
|
684
|
+
|
|
685
|
+
# Housekeep loop is installed when at least one feature requires
|
|
686
|
+
# housekeeping or the sandbox has a keepalive interval.
|
|
687
|
+
assert next_housekeep_time is not None
|
|
688
|
+
return max(0, next_housekeep_time - time.time())
|
|
689
|
+
|
|
690
690
|
while self._status not in (self.Status.SHUTTING_DOWN, self.Status.OFFLINE):
|
|
691
691
|
housekeep_start = time.time()
|
|
692
692
|
if self.keepalive_interval is not None:
|
|
693
|
+
|
|
693
694
|
if time.time() - last_ping > self.keepalive_interval:
|
|
694
695
|
try:
|
|
695
696
|
self.ping()
|
|
@@ -731,7 +732,7 @@ class BaseSandbox(interface.Sandbox):
|
|
|
731
732
|
|
|
732
733
|
self._housekeep_counter += 1
|
|
733
734
|
self.on_housekeep(time.time() - housekeep_start)
|
|
734
|
-
time.sleep(
|
|
735
|
+
time.sleep(_next_housekeep_wait_time())
|
|
735
736
|
|
|
736
737
|
#
|
|
737
738
|
# Event handlers subclasses can override.
|
|
@@ -18,12 +18,13 @@ import unittest
|
|
|
18
18
|
from langfun.env import base_sandbox
|
|
19
19
|
from langfun.env import interface
|
|
20
20
|
from langfun.env import test_utils
|
|
21
|
+
from langfun.env.event_handlers import base as event_handler_base
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
TestingEnvironment = test_utils.TestingEnvironment
|
|
24
25
|
TestingSandbox = test_utils.TestingSandbox
|
|
25
26
|
TestingFeature = test_utils.TestingFeature
|
|
26
|
-
|
|
27
|
+
TestingEventHandler = test_utils.TestingEventHandler
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
class EnvironmentTests(unittest.TestCase):
|
|
@@ -42,9 +43,8 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
42
43
|
self.assertEqual(env.min_pool_size, 0)
|
|
43
44
|
self.assertEqual(env.max_pool_size, 0)
|
|
44
45
|
self.assertEqual(env.sandbox_pool, [])
|
|
45
|
-
self.assertEqual(env.id, interface.
|
|
46
|
+
self.assertEqual(env.id, interface.Environment.Id('testing-env'))
|
|
46
47
|
self.assertEqual(env.outage_grace_period, 1)
|
|
47
|
-
self.assertEqual(env.stats_report_interval, 60)
|
|
48
48
|
self.assertEqual(env.features['test_feature'].name, 'test_feature')
|
|
49
49
|
|
|
50
50
|
self.assertIsNone(env.start_time)
|
|
@@ -60,12 +60,16 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
60
60
|
|
|
61
61
|
with env.sandbox('session1') as sb:
|
|
62
62
|
self.assertEqual(
|
|
63
|
-
sb.id, interface.
|
|
63
|
+
sb.id, interface.Sandbox.Id(environment_id=env.id, sandbox_id='0')
|
|
64
64
|
)
|
|
65
65
|
self.assertEqual(sb.session_id, 'session1')
|
|
66
66
|
self.assertEqual(sb.working_dir, '/tmp/testing-env/0')
|
|
67
67
|
self.assertTrue(sb.is_online)
|
|
68
68
|
self.assertIs(sb.test_feature, sb.features['test_feature'])
|
|
69
|
+
self.assertEqual(
|
|
70
|
+
sb.test_feature.working_dir,
|
|
71
|
+
'/tmp/testing-env/0/test_feature'
|
|
72
|
+
)
|
|
69
73
|
with self.assertRaises(AttributeError):
|
|
70
74
|
_ = sb.test_feature2
|
|
71
75
|
self.assertFalse(sb.is_online)
|
|
@@ -74,14 +78,26 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
74
78
|
with self.assertRaises(AttributeError):
|
|
75
79
|
_ = env.test_feature2
|
|
76
80
|
|
|
81
|
+
def test_del(self):
|
|
82
|
+
env = TestingEnvironment(
|
|
83
|
+
features={'test_feature': TestingFeature()},
|
|
84
|
+
pool_size=0,
|
|
85
|
+
outage_grace_period=1,
|
|
86
|
+
outage_retry_interval=0,
|
|
87
|
+
sandbox_keepalive_interval=0,
|
|
88
|
+
)
|
|
89
|
+
env.start()
|
|
90
|
+
sb = env.acquire()
|
|
91
|
+
del sb
|
|
92
|
+
del env
|
|
93
|
+
|
|
77
94
|
def test_acquire_env_offline(self):
|
|
78
95
|
env = TestingEnvironment(
|
|
79
96
|
features={'test_feature': TestingFeature()},
|
|
80
97
|
pool_size=0,
|
|
81
98
|
outage_grace_period=1,
|
|
82
99
|
outage_retry_interval=0,
|
|
83
|
-
|
|
84
|
-
stats_report_interval=1,
|
|
100
|
+
sandbox_keepalive_interval=0,
|
|
85
101
|
)
|
|
86
102
|
with self.assertRaises(interface.EnvironmentOutageError):
|
|
87
103
|
env.acquire()
|
|
@@ -92,12 +108,14 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
92
108
|
pool_size=0,
|
|
93
109
|
outage_grace_period=1,
|
|
94
110
|
outage_retry_interval=0,
|
|
95
|
-
|
|
96
|
-
stats_report_interval=1,
|
|
111
|
+
sandbox_keepalive_interval=0,
|
|
97
112
|
)
|
|
98
113
|
with env:
|
|
99
114
|
sb = env.acquire()
|
|
100
115
|
self.assertEqual(sb.status, interface.Sandbox.Status.ACQUIRED)
|
|
116
|
+
self.assertIsNone(env.working_dir)
|
|
117
|
+
self.assertIsNone(sb.working_dir)
|
|
118
|
+
self.assertIsNone(sb.test_feature.working_dir)
|
|
101
119
|
|
|
102
120
|
def test_acquire_no_pooling_with_error(self):
|
|
103
121
|
env = TestingEnvironment(
|
|
@@ -109,8 +127,7 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
109
127
|
pool_size=0,
|
|
110
128
|
outage_grace_period=1,
|
|
111
129
|
outage_retry_interval=0,
|
|
112
|
-
|
|
113
|
-
stats_report_interval=1,
|
|
130
|
+
sandbox_keepalive_interval=0,
|
|
114
131
|
)
|
|
115
132
|
with env:
|
|
116
133
|
with self.assertRaises(interface.EnvironmentOutageError):
|
|
@@ -122,8 +139,7 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
122
139
|
pool_size=1,
|
|
123
140
|
outage_grace_period=1,
|
|
124
141
|
outage_retry_interval=0,
|
|
125
|
-
|
|
126
|
-
stats_report_interval=1,
|
|
142
|
+
sandbox_keepalive_interval=0,
|
|
127
143
|
)
|
|
128
144
|
with env:
|
|
129
145
|
sb = env.acquire()
|
|
@@ -135,8 +151,7 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
135
151
|
pool_size=1,
|
|
136
152
|
outage_grace_period=1,
|
|
137
153
|
outage_retry_interval=0,
|
|
138
|
-
|
|
139
|
-
stats_report_interval=1,
|
|
154
|
+
sandbox_keepalive_interval=0,
|
|
140
155
|
)
|
|
141
156
|
with env:
|
|
142
157
|
sb = env.acquire()
|
|
@@ -150,17 +165,76 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
150
165
|
pool_size=(1, 3),
|
|
151
166
|
outage_grace_period=1,
|
|
152
167
|
outage_retry_interval=0,
|
|
153
|
-
|
|
154
|
-
stats_report_interval=1,
|
|
168
|
+
sandbox_keepalive_interval=0,
|
|
155
169
|
)
|
|
156
170
|
with env:
|
|
157
171
|
self.assertEqual(len(env.sandbox_pool), 1)
|
|
172
|
+
self.assertEqual(
|
|
173
|
+
env.stats(),
|
|
174
|
+
{
|
|
175
|
+
'sandbox': {
|
|
176
|
+
'created': 0,
|
|
177
|
+
'setting_up': 0,
|
|
178
|
+
'ready': 1,
|
|
179
|
+
'acquired': 0,
|
|
180
|
+
'in_session': 0,
|
|
181
|
+
'exiting_session': 0,
|
|
182
|
+
'shutting_down': 0,
|
|
183
|
+
'offline': 0,
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
)
|
|
158
187
|
sb = env.acquire()
|
|
159
188
|
self.assertEqual(sb.status, interface.Sandbox.Status.ACQUIRED)
|
|
189
|
+
self.assertEqual(
|
|
190
|
+
env.stats(),
|
|
191
|
+
{
|
|
192
|
+
'sandbox': {
|
|
193
|
+
'created': 0,
|
|
194
|
+
'setting_up': 0,
|
|
195
|
+
'ready': 0,
|
|
196
|
+
'acquired': 1,
|
|
197
|
+
'in_session': 0,
|
|
198
|
+
'exiting_session': 0,
|
|
199
|
+
'shutting_down': 0,
|
|
200
|
+
'offline': 0,
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
)
|
|
160
204
|
self.assertEqual(len(env.sandbox_pool), 1)
|
|
161
205
|
sb2 = env.acquire()
|
|
162
206
|
self.assertEqual(sb2.status, interface.Sandbox.Status.ACQUIRED)
|
|
163
207
|
self.assertEqual(len(env.sandbox_pool), 2)
|
|
208
|
+
self.assertEqual(
|
|
209
|
+
env.stats(),
|
|
210
|
+
{
|
|
211
|
+
'sandbox': {
|
|
212
|
+
'created': 0,
|
|
213
|
+
'setting_up': 0,
|
|
214
|
+
'ready': 0,
|
|
215
|
+
'acquired': 2,
|
|
216
|
+
'in_session': 0,
|
|
217
|
+
'exiting_session': 0,
|
|
218
|
+
'shutting_down': 0,
|
|
219
|
+
'offline': 0,
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
self.assertEqual(
|
|
224
|
+
env.stats(),
|
|
225
|
+
{
|
|
226
|
+
'sandbox': {
|
|
227
|
+
'created': 0,
|
|
228
|
+
'setting_up': 0,
|
|
229
|
+
'ready': 0,
|
|
230
|
+
'acquired': 0,
|
|
231
|
+
'in_session': 0,
|
|
232
|
+
'exiting_session': 0,
|
|
233
|
+
'shutting_down': 0,
|
|
234
|
+
'offline': 0,
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
)
|
|
164
238
|
|
|
165
239
|
def test_acquire_with_growing_pool_failure(self):
|
|
166
240
|
env = TestingEnvironment(
|
|
@@ -168,8 +242,7 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
168
242
|
pool_size=(1, 3),
|
|
169
243
|
outage_grace_period=1,
|
|
170
244
|
outage_retry_interval=0,
|
|
171
|
-
|
|
172
|
-
stats_report_interval=1,
|
|
245
|
+
sandbox_keepalive_interval=0,
|
|
173
246
|
)
|
|
174
247
|
with env:
|
|
175
248
|
self.assertEqual(len(env.sandbox_pool), 1)
|
|
@@ -184,15 +257,14 @@ class EnvironmentTests(unittest.TestCase):
|
|
|
184
257
|
with self.assertRaises(interface.EnvironmentOutageError):
|
|
185
258
|
env.acquire()
|
|
186
259
|
|
|
187
|
-
def
|
|
260
|
+
def test_housekeep_error(self):
|
|
188
261
|
env = TestingEnvironment(
|
|
189
262
|
features={'test_feature': TestingFeature()},
|
|
190
263
|
pool_size=1,
|
|
191
264
|
proactive_session_setup=True,
|
|
192
265
|
outage_grace_period=1,
|
|
193
266
|
outage_retry_interval=0,
|
|
194
|
-
|
|
195
|
-
stats_report_interval=1,
|
|
267
|
+
sandbox_keepalive_interval=0,
|
|
196
268
|
)
|
|
197
269
|
with env:
|
|
198
270
|
self.assertEqual(len(env.sandbox_pool), 1)
|
|
@@ -216,7 +288,7 @@ class SandboxStatusTests(unittest.TestCase):
|
|
|
216
288
|
|
|
217
289
|
def setUp(self):
|
|
218
290
|
super().setUp()
|
|
219
|
-
self.event_handler =
|
|
291
|
+
self.event_handler = TestingEventHandler(
|
|
220
292
|
log_sandbox_status=True,
|
|
221
293
|
log_feature_setup=True,
|
|
222
294
|
log_session_setup=True,
|
|
@@ -246,6 +318,7 @@ class SandboxStatusTests(unittest.TestCase):
|
|
|
246
318
|
'feature2': TestingFeature(),
|
|
247
319
|
},
|
|
248
320
|
)
|
|
321
|
+
self.assertFalse(env.enable_pooling)
|
|
249
322
|
with env:
|
|
250
323
|
with env.sandbox('session1') as sb:
|
|
251
324
|
sb.shell('echo "hello"')
|
|
@@ -294,6 +367,7 @@ class SandboxStatusTests(unittest.TestCase):
|
|
|
294
367
|
pool_size=1,
|
|
295
368
|
proactive_session_setup=True,
|
|
296
369
|
)
|
|
370
|
+
self.assertTrue(env.enable_pooling)
|
|
297
371
|
with env:
|
|
298
372
|
with env.sandbox('session1') as sb:
|
|
299
373
|
sb.shell('echo "hello"')
|
|
@@ -343,7 +417,7 @@ class SandboxStatusTests(unittest.TestCase):
|
|
|
343
417
|
features={'test_feature': TestingFeature(setup_session_delay=0.5)},
|
|
344
418
|
pool_size=1,
|
|
345
419
|
)
|
|
346
|
-
event_handler =
|
|
420
|
+
event_handler = TestingEventHandler(
|
|
347
421
|
log_sandbox_status=True,
|
|
348
422
|
log_feature_setup=True,
|
|
349
423
|
log_session_setup=True,
|
|
@@ -919,6 +993,7 @@ class SandboxStatusTests(unittest.TestCase):
|
|
|
919
993
|
self.assertEqual(len(sb.state_errors), 0)
|
|
920
994
|
sb.shell('echo bar')
|
|
921
995
|
self.assertEqual(sb.status, interface.Sandbox.Status.IN_SESSION)
|
|
996
|
+
sb.wait_until_not(interface.Sandbox.Status.SETTING_UP)
|
|
922
997
|
self.assertEqual(sb.status, interface.Sandbox.Status.READY)
|
|
923
998
|
self.assertEqual(
|
|
924
999
|
self.event_handler.logs,
|
|
@@ -1020,7 +1095,7 @@ class SandboxActivityTests(unittest.TestCase):
|
|
|
1020
1095
|
env = TestingEnvironment(
|
|
1021
1096
|
features={'test_feature': TestingFeature(housekeep_interval=0)},
|
|
1022
1097
|
pool_size=1,
|
|
1023
|
-
|
|
1098
|
+
sandbox_keepalive_interval=0,
|
|
1024
1099
|
)
|
|
1025
1100
|
with env:
|
|
1026
1101
|
with env.sandbox('session1') as sb:
|
|
@@ -1037,7 +1112,7 @@ class SandboxActivityTests(unittest.TestCase):
|
|
|
1037
1112
|
pool_size=1,
|
|
1038
1113
|
outage_grace_period=0,
|
|
1039
1114
|
outage_retry_interval=0,
|
|
1040
|
-
|
|
1115
|
+
sandbox_keepalive_interval=0,
|
|
1041
1116
|
)
|
|
1042
1117
|
with env:
|
|
1043
1118
|
with env.sandbox('session1') as sb:
|
|
@@ -1052,7 +1127,7 @@ class SandboxActivityTests(unittest.TestCase):
|
|
|
1052
1127
|
while sb.housekeep_counter == housekeep_count or (
|
|
1053
1128
|
sb.status == interface.Sandbox.Status.IN_SESSION
|
|
1054
1129
|
):
|
|
1055
|
-
time.sleep(0.
|
|
1130
|
+
time.sleep(0.01)
|
|
1056
1131
|
self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
|
|
1057
1132
|
|
|
1058
1133
|
def test_remove_event_handler(self):
|
|
@@ -1061,10 +1136,9 @@ class SandboxActivityTests(unittest.TestCase):
|
|
|
1061
1136
|
pool_size=1,
|
|
1062
1137
|
outage_grace_period=0,
|
|
1063
1138
|
outage_retry_interval=0,
|
|
1064
|
-
|
|
1065
|
-
stats_report_interval=1,
|
|
1139
|
+
sandbox_keepalive_interval=0,
|
|
1066
1140
|
)
|
|
1067
|
-
event_handler =
|
|
1141
|
+
event_handler = TestingEventHandler()
|
|
1068
1142
|
with env:
|
|
1069
1143
|
with env.sandbox('session1') as sb:
|
|
1070
1144
|
sb.add_event_handler(event_handler)
|
|
@@ -1082,21 +1156,20 @@ class SandboxServiceTests(unittest.TestCase):
|
|
|
1082
1156
|
def setUp(self):
|
|
1083
1157
|
super().setUp()
|
|
1084
1158
|
self.maxDiff = None
|
|
1085
|
-
self.event_handler =
|
|
1159
|
+
self.event_handler = TestingEventHandler()
|
|
1086
1160
|
self.env = TestingEnvironment(
|
|
1087
1161
|
features={'test_feature': TestingFeature()},
|
|
1088
1162
|
pool_size=0,
|
|
1089
1163
|
outage_grace_period=0,
|
|
1090
1164
|
outage_retry_interval=0,
|
|
1091
|
-
|
|
1165
|
+
sandbox_keepalive_interval=0,
|
|
1092
1166
|
event_handlers=[self.event_handler],
|
|
1093
|
-
stats_report_interval=1,
|
|
1094
1167
|
random_seed=1,
|
|
1095
1168
|
)
|
|
1096
1169
|
|
|
1097
1170
|
def test_service_call_activity_log(self):
|
|
1098
1171
|
|
|
1099
|
-
class CustomEventHandler(
|
|
1172
|
+
class CustomEventHandler(event_handler_base.EventHandler):
|
|
1100
1173
|
|
|
1101
1174
|
def __init__(self):
|
|
1102
1175
|
self.calls = []
|