From 8ba66cc12c3bb678dfc13ef996437d98cc2cb9dc Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Tue, 21 Jan 2025 16:30:52 -0500 Subject: [PATCH 01/11] Test with Python 3.13 - Switch bytecode wrapping with wrapt.wrap_function_wrapper - Implement unpatching - Add patching tests --- ddtrace/contrib/internal/openai/patch.py | 244 ++++++++++--------- riotfile.py | 4 +- tests/contrib/openai/test_openai_patch.py | 272 +++++++++++++++++++++- tests/contrib/openai/test_openai_v0.py | 38 --- tests/contrib/openai/test_openai_v1.py | 52 ----- 5 files changed, 393 insertions(+), 217 deletions(-) diff --git a/ddtrace/contrib/internal/openai/patch.py b/ddtrace/contrib/internal/openai/patch.py index d87b06b3aba..77f7689a70e 100644 --- a/ddtrace/contrib/internal/openai/patch.py +++ b/ddtrace/contrib/internal/openai/patch.py @@ -6,12 +6,14 @@ from ddtrace import config from ddtrace.contrib.internal.openai import _endpoint_hooks from ddtrace.contrib.internal.openai.utils import _format_openai_api_key +from ddtrace.contrib.trace_utils import unwrap +from ddtrace.contrib.trace_utils import with_traced_module +from ddtrace.contrib.trace_utils import wrap from ddtrace.internal.logger import get_logger from ddtrace.internal.schema import schematize_service_name from ddtrace.internal.utils.formats import asbool from ddtrace.internal.utils.formats import deep_getattr from ddtrace.internal.utils.version import parse_version -from ddtrace.internal.wrapping import wrap from ddtrace.llmobs._integrations import OpenAIIntegration from ddtrace.trace import Pin @@ -114,10 +116,6 @@ def get_version(): } -def _wrap_classmethod(obj, wrapper): - wrap(obj.__func__, wrapper) - - def patch(): # Avoid importing openai at the module level, eventually will be an import hook import openai @@ -127,69 +125,103 @@ def patch(): Pin().onto(openai) integration = OpenAIIntegration(integration_config=config.openai, openai=openai) + openai._datadog_integration = integration if OPENAI_VERSION >= (1, 0, 0): if OPENAI_VERSION >= (1, 8, 0): - wrap(openai._base_client.SyncAPIClient._process_response, _patched_convert(openai, integration)) - wrap(openai._base_client.AsyncAPIClient._process_response, _patched_convert(openai, integration)) + wrap(openai, "_base_client.SyncAPIClient._process_response", patched_convert(openai)) + wrap(openai, "_base_client.AsyncAPIClient._process_response", patched_convert(openai)) else: - wrap(openai._base_client.BaseClient._process_response, _patched_convert(openai, integration)) - wrap(openai.OpenAI.__init__, _patched_client_init(openai, integration)) - wrap(openai.AsyncOpenAI.__init__, _patched_client_init(openai, integration)) - wrap(openai.AzureOpenAI.__init__, _patched_client_init(openai, integration)) - wrap(openai.AsyncAzureOpenAI.__init__, _patched_client_init(openai, integration)) + wrap(openai, "_base_client.BaseClient._process_response", patched_convert(openai)) + wrap(openai, "OpenAI.__init__", patched_client_init(openai)) + wrap(openai, "AsyncOpenAI.__init__", patched_client_init(openai)) + wrap(openai, "AzureOpenAI.__init__", patched_client_init(openai)) + wrap(openai, "AsyncAzureOpenAI.__init__", patched_client_init(openai)) for resource, method_hook_dict in _RESOURCES.items(): if deep_getattr(openai.resources, resource) is None: continue for method_name, endpoint_hook in method_hook_dict.items(): - sync_method = deep_getattr(openai.resources, "%s.%s" % (resource, method_name)) - async_method = deep_getattr( - openai.resources, "%s.%s" % (".Async".join(resource.split(".")), method_name) - ) - wrap(sync_method, _patched_endpoint(openai, integration, endpoint_hook)) - wrap(async_method, _patched_endpoint_async(openai, integration, endpoint_hook)) + sync_method = "resources.{}.{}".format(resource, method_name) + async_method = "resources.{}.{}".format(".Async".join(resource.split(".")), method_name) + wrap(openai, sync_method, _patched_endpoint(openai, endpoint_hook)) + wrap(openai, async_method, _patched_endpoint_async(openai, endpoint_hook)) else: import openai.api_requestor - wrap(openai.api_requestor._make_session, _patched_make_session) - wrap(openai.util.convert_to_openai_object, _patched_convert(openai, integration)) + wrap(openai, "api_requestor._make_session", _patched_make_session) + wrap(openai, "util.convert_to_openai_object", patched_convert(openai)) for resource, method_hook_dict in _RESOURCES.items(): if deep_getattr(openai.api_resources, resource) is None: continue for method_name, endpoint_hook in method_hook_dict.items(): - sync_method = deep_getattr(openai.api_resources, "%s.%s" % (resource, method_name)) - async_method = deep_getattr(openai.api_resources, "%s.a%s" % (resource, method_name)) - _wrap_classmethod(sync_method, _patched_endpoint(openai, integration, endpoint_hook)) - _wrap_classmethod(async_method, _patched_endpoint_async(openai, integration, endpoint_hook)) + sync_method = "api_resources.{}.{}".format(resource, method_name) + async_method = "api_resources.{}.a{}".format(resource, method_name) + wrap(openai, sync_method, _patched_endpoint(openai, endpoint_hook)) + wrap(openai, async_method, _patched_endpoint_async(openai, endpoint_hook)) openai.__datadog_patch = True def unpatch(): - # FIXME: add unpatching. The current wrapping.unwrap method requires - # the wrapper function to be provided which we don't keep a reference to. - pass + import openai + + if not getattr(openai, "__datadog_patch", False): + return + + openai.__datadog_patch = False + + if OPENAI_VERSION >= (1, 0, 0): + if OPENAI_VERSION >= (1, 8, 0): + unwrap(openai._base_client.SyncAPIClient, "_process_response") + unwrap(openai._base_client.AsyncAPIClient, "_process_response") + else: + unwrap(openai._base_client.BaseClient, "_process_response") + unwrap(openai.OpenAI, "__init__") + unwrap(openai.AsyncOpenAI, "__init__") + unwrap(openai.AzureOpenAI, "__init__") + unwrap(openai.AsyncAzureOpenAI, "__init__") + + for resource, method_hook_dict in _RESOURCES.items(): + if deep_getattr(openai.resources, resource) is None: + continue + for method_name, _ in method_hook_dict.items(): + sync_resource = deep_getattr(openai.resources, resource) + async_resource = deep_getattr(openai.resources, ".Async".join(resource.split("."))) + unwrap(sync_resource, method_name) + unwrap(async_resource, method_name) + else: + import openai.api_requestor + + unwrap(openai.api_requestor, "_make_session") + wrap(openai.util, "convert_to_openai_object") + + for resource, method_hook_dict in _RESOURCES.items(): + if deep_getattr(openai.api_resources, resource) is None: + continue + for method_name, _ in method_hook_dict.items(): + resource_obj = deep_getattr(openai.api_resources, resource) + unwrap(resource_obj, method_name) + unwrap(resource_obj, "a{}".format(method_name)) + delattr(openai, "_datadog_integration") -def _patched_client_init(openai, integration): + +@with_traced_module +def patched_client_init(openai, pin, func, instance, args, kwargs): """ Patch for `openai.OpenAI/AsyncOpenAI` client init methods to add the client object to the OpenAIIntegration object. """ - - def patched_client_init(func, args, kwargs): - func(*args, **kwargs) - client = args[0] - integration._client = client - api_key = kwargs.get("api_key") - if api_key is None: - api_key = client.api_key - if api_key is not None: - integration.user_api_key = api_key - return - - return patched_client_init + func(*args, **kwargs) + integration = openai._datadog_integration + integration._client = instance + api_key = kwargs.get("api_key") + if api_key is None: + api_key = instance.api_key + if api_key is not None: + integration.user_api_key = api_key + return def _patched_make_session(func, args, kwargs): @@ -238,18 +270,10 @@ def _traced_endpoint(endpoint_hook, integration, pin, args, kwargs): integration.metric(span, "dist", "request.duration", span.duration_ns) -def _patched_endpoint(openai, integration, patch_hook): - def patched_endpoint(func, args, kwargs): - # FIXME: this is a temporary workaround for the fact that our bytecode wrapping seems to modify - # a function keyword argument into a cell when it shouldn't. This is only an issue on - # Python 3.11+. - if sys.version_info >= (3, 11) and kwargs.get("encoding_format", None): - kwargs["encoding_format"] = kwargs["encoding_format"].cell_contents - - pin = Pin._find(openai, args[0]) - if not pin or not pin.enabled(): - return func(*args, **kwargs) - +def _patched_endpoint(openai, patch_hook): + @with_traced_module + def patched_endpoint(openai, pin, func, instance, args, kwargs): + integration = openai._datadog_integration g = _traced_endpoint(patch_hook, integration, pin, args, kwargs) g.send(None) resp, err = None, None @@ -267,21 +291,14 @@ def patched_endpoint(func, args, kwargs): # This return takes priority over `return resp` return e.value # noqa: B012 - return patched_endpoint + return patched_endpoint(openai) -def _patched_endpoint_async(openai, integration, patch_hook): +def _patched_endpoint_async(openai, patch_hook): # Same as _patched_endpoint but async - async def patched_endpoint(func, args, kwargs): - # FIXME: this is a temporary workaround for the fact that our bytecode wrapping seems to modify - # a function keyword argument into a cell when it shouldn't. This is only an issue on - # Python 3.11+. - if sys.version_info >= (3, 11) and kwargs.get("encoding_format", None): - kwargs["encoding_format"] = kwargs["encoding_format"].cell_contents - - pin = Pin._find(openai, args[0]) - if not pin or not pin.enabled(): - return await func(*args, **kwargs) + @with_traced_module + async def patched_endpoint(openai, pin, func, instance, args, kwargs): + integration = openai._datadog_integration g = _traced_endpoint(patch_hook, integration, pin, args, kwargs) g.send(None) resp, err = None, None @@ -304,59 +321,54 @@ async def patched_endpoint(func, args, kwargs): # This return takes priority over `return resp` return e.value # noqa: B012 - return patched_endpoint + return patched_endpoint(openai) -def _patched_convert(openai, integration): - def patched_convert(func, args, kwargs): - """Patch convert captures header information in the openai response""" - pin = Pin.get_from(openai) - if not pin or not pin.enabled(): - return func(*args, **kwargs) +@with_traced_module +def patched_convert(openai, pin, func, instance, args, kwargs): + """Patch convert captures header information in the openai response""" + integration = openai._datadog_integration + span = pin.tracer.current_span() + if not span: + return func(*args, **kwargs) - span = pin.tracer.current_span() - if not span: + if OPENAI_VERSION < (1, 0, 0): + resp = args[0] + if not isinstance(resp, openai.openai_response.OpenAIResponse): return func(*args, **kwargs) - - if OPENAI_VERSION < (1, 0, 0): - resp = args[0] - if not isinstance(resp, openai.openai_response.OpenAIResponse): - return func(*args, **kwargs) - headers = resp._headers - else: - resp = kwargs.get("response", {}) - headers = resp.headers - # This function is called for each chunk in the stream. - # To prevent needlessly setting the same tags for each chunk, short-circuit here. - if span.get_tag("openai.organization.name") is not None: - return func(*args, **kwargs) - if headers.get("openai-organization"): - org_name = headers.get("openai-organization") - span.set_tag_str("openai.organization.name", org_name) - - # Gauge total rate limit - if headers.get("x-ratelimit-limit-requests"): - v = headers.get("x-ratelimit-limit-requests") - if v is not None: - integration.metric(span, "gauge", "ratelimit.requests", int(v)) - span.set_metric("openai.organization.ratelimit.requests.limit", int(v)) - if headers.get("x-ratelimit-limit-tokens"): - v = headers.get("x-ratelimit-limit-tokens") - if v is not None: - integration.metric(span, "gauge", "ratelimit.tokens", int(v)) - span.set_metric("openai.organization.ratelimit.tokens.limit", int(v)) - # Gauge and set span info for remaining requests and tokens - if headers.get("x-ratelimit-remaining-requests"): - v = headers.get("x-ratelimit-remaining-requests") - if v is not None: - integration.metric(span, "gauge", "ratelimit.remaining.requests", int(v)) - span.set_metric("openai.organization.ratelimit.requests.remaining", int(v)) - if headers.get("x-ratelimit-remaining-tokens"): - v = headers.get("x-ratelimit-remaining-tokens") - if v is not None: - integration.metric(span, "gauge", "ratelimit.remaining.tokens", int(v)) - span.set_metric("openai.organization.ratelimit.tokens.remaining", int(v)) - + headers = resp._headers + else: + resp = kwargs.get("response", {}) + headers = resp.headers + # This function is called for each chunk in the stream. + # To prevent needlessly setting the same tags for each chunk, short-circuit here. + if span.get_tag("openai.organization.name") is not None: return func(*args, **kwargs) - - return patched_convert + if headers.get("openai-organization"): + org_name = headers.get("openai-organization") + span.set_tag_str("openai.organization.name", org_name) + + # Gauge total rate limit + if headers.get("x-ratelimit-limit-requests"): + v = headers.get("x-ratelimit-limit-requests") + if v is not None: + integration.metric(span, "gauge", "ratelimit.requests", int(v)) + span.set_metric("openai.organization.ratelimit.requests.limit", int(v)) + if headers.get("x-ratelimit-limit-tokens"): + v = headers.get("x-ratelimit-limit-tokens") + if v is not None: + integration.metric(span, "gauge", "ratelimit.tokens", int(v)) + span.set_metric("openai.organization.ratelimit.tokens.limit", int(v)) + # Gauge and set span info for remaining requests and tokens + if headers.get("x-ratelimit-remaining-requests"): + v = headers.get("x-ratelimit-remaining-requests") + if v is not None: + integration.metric(span, "gauge", "ratelimit.remaining.requests", int(v)) + span.set_metric("openai.organization.ratelimit.requests.remaining", int(v)) + if headers.get("x-ratelimit-remaining-tokens"): + v = headers.get("x-ratelimit-remaining-tokens") + if v is not None: + integration.metric(span, "gauge", "ratelimit.remaining.tokens", int(v)) + span.set_metric("openai.organization.ratelimit.tokens.remaining", int(v)) + + return func(*args, **kwargs) diff --git a/riotfile.py b/riotfile.py index b52fa77cbe1..d139a9bfcc2 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2504,14 +2504,14 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT }, ), Venv( - pys=select_pys(min_version="3.7", max_version="3.11"), + pys=select_pys(min_version="3.7"), pkgs={ "openai[embeddings,datalib]": ["==1.1.1", "==1.30.1"], "pillow": "==9.5.0", }, ), Venv( - pys=select_pys(min_version="3.8", max_version="3.11"), + pys=select_pys(min_version="3.8"), pkgs={ "openai[datalib]": ["==1.30.1"], "tiktoken": latest, diff --git a/tests/contrib/openai/test_openai_patch.py b/tests/contrib/openai/test_openai_patch.py index caab79117cf..50a566626dd 100644 --- a/tests/contrib/openai/test_openai_patch.py +++ b/tests/contrib/openai/test_openai_patch.py @@ -3,14 +3,10 @@ # removed the ``_generated`` suffix from the file name, to prevent the content # from being overwritten by future re-generations. +from ddtrace.contrib.internal.openai.patch import OPENAI_VERSION from ddtrace.contrib.internal.openai.patch import get_version from ddtrace.contrib.internal.openai.patch import patch - - -try: - from ddtrace.contrib.internal.openai.patch import unpatch -except ImportError: - unpatch = None +from ddtrace.contrib.internal.openai.patch import unpatch from tests.contrib.patch import PatchTestCase @@ -22,10 +18,268 @@ class TestOpenaiPatch(PatchTestCase.Base): __get_version__ = get_version def assert_module_patched(self, openai): - pass + if OPENAI_VERSION >= (1, 0, 0): + if OPENAI_VERSION >= (1, 8, 0): + self.assert_wrapped(openai._base_client.SyncAPIClient._process_response) + self.assert_wrapped(openai._base_client.AsyncAPIClient._process_response) + else: + self.assert_wrapped(openai._base_client.BaseClient._process_response) + self.assert_wrapped(openai.OpenAI.__init__) + self.assert_wrapped(openai.AsyncOpenAI.__init__) + self.assert_wrapped(openai.AzureOpenAI.__init__) + self.assert_wrapped(openai.AsyncAzureOpenAI.__init__) + self.assert_wrapped(openai.resources.models.Models.list) + self.assert_wrapped(openai.resources.models.Models.retrieve) + self.assert_wrapped(openai.resources.models.Models.delete) + self.assert_wrapped(openai.resources.models.AsyncModels.list) + self.assert_wrapped(openai.resources.models.AsyncModels.retrieve) + self.assert_wrapped(openai.resources.models.AsyncModels.delete) + self.assert_wrapped(openai.resources.completions.Completions.create) + self.assert_wrapped(openai.resources.chat.Completions.create) + self.assert_wrapped(openai.resources.completions.AsyncCompletions.create) + self.assert_wrapped(openai.resources.chat.AsyncCompletions.create) + self.assert_wrapped(openai.resources.images.Images.generate) + self.assert_wrapped(openai.resources.images.Images.edit) + self.assert_wrapped(openai.resources.images.Images.create_variation) + self.assert_wrapped(openai.resources.images.AsyncImages.generate) + self.assert_wrapped(openai.resources.images.AsyncImages.edit) + self.assert_wrapped(openai.resources.images.AsyncImages.create_variation) + self.assert_wrapped(openai.resources.audio.Transcriptions.create) + self.assert_wrapped(openai.resources.audio.Translations.create) + self.assert_wrapped(openai.resources.audio.AsyncTranscriptions.create) + self.assert_wrapped(openai.resources.audio.AsyncTranslations.create) + self.assert_wrapped(openai.resources.embeddings.Embeddings.create) + self.assert_wrapped(openai.resources.moderations.Moderations.create) + self.assert_wrapped(openai.resources.embeddings.AsyncEmbeddings.create) + self.assert_wrapped(openai.resources.moderations.AsyncModerations.create) + self.assert_wrapped(openai.resources.files.Files.create) + self.assert_wrapped(openai.resources.files.Files.retrieve) + self.assert_wrapped(openai.resources.files.Files.list) + self.assert_wrapped(openai.resources.files.Files.delete) + self.assert_wrapped(openai.resources.files.Files.retrieve_content) + self.assert_wrapped(openai.resources.files.AsyncFiles.create) + self.assert_wrapped(openai.resources.files.AsyncFiles.retrieve) + self.assert_wrapped(openai.resources.files.AsyncFiles.list) + self.assert_wrapped(openai.resources.files.AsyncFiles.delete) + self.assert_wrapped(openai.resources.files.AsyncFiles.retrieve_content) + + else: + self.assert_wrapped(openai.api_resources.completion.Completion.create) + self.assert_wrapped(openai.api_resources.completion.Completion.acreate) + self.assert_wrapped(openai.api_requestor._make_session) + self.assert_wrapped(openai.util.convert_to_openai_object) + self.assert_wrapped(openai.api_resources.embedding.Embedding.create) + self.assert_wrapped(openai.api_resources.embedding.Embedding.acreate) + if hasattr(openai, "Model"): + self.assert_wrapped(openai.api_resources.model.Model.list) + self.assert_wrapped(openai.api_resources.model.Model.retrieve) + self.assert_wrapped(openai.api_resources.model.Model.delete) + self.assert_wrapped(openai.api_resources.model.Model.alist) + self.assert_wrapped(openai.api_resources.model.Model.aretrieve) + self.assert_wrapped(openai.api_resources.model.Model.adelete) + if hasattr(openai, "ChatCompletion"): + self.assert_wrapped(openai.api_resources.chat_completion.ChatCompletion.create) + self.assert_wrapped(openai.api_resources.chat_completion.ChatCompletion.acreate) + if hasattr(openai, "Image"): + self.assert_wrapped(openai.api_resources.image.Image.create) + self.assert_wrapped(openai.api_resources.image.Image.acreate) + self.assert_wrapped(openai.api_resources.image.Image.create_edit) + self.assert_wrapped(openai.api_resources.image.Image.acreate_edit) + self.assert_wrapped(openai.api_resources.image.Image.create_variation) + self.assert_wrapped(openai.api_resources.image.Image.acreate_variation) + if hasattr(openai, "Audio"): + self.assert_wrapped(openai.api_resources.audio.Audio.transcribe) + self.assert_wrapped(openai.api_resources.audio.Audio.atranscribe) + self.assert_wrapped(openai.api_resources.audio.Audio.translate) + self.assert_wrapped(openai.api_resources.audio.Audio.atranslate) + if hasattr(openai, "Moderation"): + self.assert_wrapped(openai.api_resources.moderation.Moderation.create) + self.assert_wrapped(openai.api_resources.moderation.Moderation.acreate) + if hasattr(openai, "File"): + self.assert_wrapped(openai.api_resources.file.File.create) + self.assert_wrapped(openai.api_resources.file.File.retrieve) + self.assert_wrapped(openai.api_resources.file.File.list) + self.assert_wrapped(openai.api_resources.file.File.delete) + self.assert_wrapped(openai.api_resources.file.File.aretrieve_content) + self.assert_wrapped(openai.api_resources.file.File.acreate) + self.assert_wrapped(openai.api_resources.file.File.aretrieve) + self.assert_wrapped(openai.api_resources.file.File.alist) + self.assert_wrapped(openai.api_resources.file.File.adelete) def assert_not_module_patched(self, openai): - pass + if OPENAI_VERSION >= (1, 0, 0): + if OPENAI_VERSION >= (1, 8, 0): + self.assert_not_wrapped(openai._base_client.SyncAPIClient._process_response) + self.assert_not_wrapped(openai._base_client.AsyncAPIClient._process_response) + else: + self.assert_not_wrapped(openai._base_client.BaseClient._process_response) + self.assert_not_wrapped(openai.OpenAI.__init__) + self.assert_not_wrapped(openai.AsyncOpenAI.__init__) + self.assert_not_wrapped(openai.AzureOpenAI.__init__) + self.assert_not_wrapped(openai.AsyncAzureOpenAI.__init__) + self.assert_not_wrapped(openai.resources.models.Models.list) + self.assert_not_wrapped(openai.resources.models.Models.retrieve) + self.assert_not_wrapped(openai.resources.models.Models.delete) + self.assert_not_wrapped(openai.resources.models.AsyncModels.list) + self.assert_not_wrapped(openai.resources.models.AsyncModels.retrieve) + self.assert_not_wrapped(openai.resources.models.AsyncModels.delete) + self.assert_not_wrapped(openai.resources.completions.Completions.create) + self.assert_not_wrapped(openai.resources.chat.Completions.create) + self.assert_not_wrapped(openai.resources.completions.AsyncCompletions.create) + self.assert_not_wrapped(openai.resources.chat.AsyncCompletions.create) + self.assert_not_wrapped(openai.resources.images.Images.generate) + self.assert_not_wrapped(openai.resources.images.Images.edit) + self.assert_not_wrapped(openai.resources.images.Images.create_variation) + self.assert_not_wrapped(openai.resources.images.AsyncImages.generate) + self.assert_not_wrapped(openai.resources.images.AsyncImages.edit) + self.assert_not_wrapped(openai.resources.images.AsyncImages.create_variation) + self.assert_not_wrapped(openai.resources.audio.Transcriptions.create) + self.assert_not_wrapped(openai.resources.audio.Translations.create) + self.assert_not_wrapped(openai.resources.audio.AsyncTranscriptions.create) + self.assert_not_wrapped(openai.resources.audio.AsyncTranslations.create) + self.assert_not_wrapped(openai.resources.embeddings.Embeddings.create) + self.assert_not_wrapped(openai.resources.moderations.Moderations.create) + self.assert_not_wrapped(openai.resources.embeddings.AsyncEmbeddings.create) + self.assert_not_wrapped(openai.resources.moderations.AsyncModerations.create) + self.assert_not_wrapped(openai.resources.files.Files.create) + self.assert_not_wrapped(openai.resources.files.Files.retrieve) + self.assert_not_wrapped(openai.resources.files.Files.list) + self.assert_not_wrapped(openai.resources.files.Files.delete) + self.assert_not_wrapped(openai.resources.files.AsyncFiles.retrieve_content) + self.assert_not_wrapped(openai.resources.files.AsyncFiles.create) + self.assert_not_wrapped(openai.resources.files.AsyncFiles.retrieve) + self.assert_not_wrapped(openai.resources.files.AsyncFiles.list) + self.assert_not_wrapped(openai.resources.files.AsyncFiles.delete) + self.assert_not_wrapped(openai.resources.files.AsyncFiles.retrieve_content) + + else: + self.assert_not_wrapped(openai.api_resources.completion.Completion.create) + self.assert_not_wrapped(openai.api_resources.completion.Completion.acreate) + self.assert_not_wrapped(openai.api_requestor._make_session) + self.assert_not_wrapped(openai.util.convert_to_openai_object) + self.assert_not_wrapped(openai.api_resources.embedding.Embedding.create) + self.assert_not_wrapped(openai.api_resources.embedding.Embedding.acreate) + if hasattr(openai, "Model"): + self.assert_not_wrapped(openai.api_resources.model.Model.list) + self.assert_not_wrapped(openai.api_resources.model.Model.retrieve) + self.assert_not_wrapped(openai.api_resources.model.Model.delete) + self.assert_not_wrapped(openai.api_resources.model.Model.alist) + self.assert_not_wrapped(openai.api_resources.model.Model.aretrieve) + self.assert_not_wrapped(openai.api_resources.model.Model.adelete) + if hasattr(openai, "ChatCompletion"): + self.assert_not_wrapped(openai.api_resources.chat_completion.ChatCompletion.create) + self.assert_not_wrapped(openai.api_resources.chat_completion.ChatCompletion.acreate) + if hasattr(openai, "Image"): + self.assert_not_wrapped(openai.api_resources.image.Image.create) + self.assert_not_wrapped(openai.api_resources.image.Image.acreate) + self.assert_not_wrapped(openai.api_resources.image.Image.create_edit) + self.assert_not_wrapped(openai.api_resources.image.Image.acreate_edit) + self.assert_not_wrapped(openai.api_resources.image.Image.create_variation) + self.assert_not_wrapped(openai.api_resources.image.Image.acreate_variation) + if hasattr(openai, "Audio"): + self.assert_not_wrapped(openai.api_resources.audio.Audio.transcribe) + self.assert_not_wrapped(openai.api_resources.audio.Audio.atranscribe) + self.assert_not_wrapped(openai.api_resources.audio.Audio.translate) + self.assert_not_wrapped(openai.api_resources.audio.Audio.atranslate) + if hasattr(openai, "Moderation"): + self.assert_not_wrapped(openai.api_resources.moderation.Moderation.create) + self.assert_not_wrapped(openai.api_resources.moderation.Moderation.acreate) + if hasattr(openai, "File"): + self.assert_not_wrapped(openai.api_resources.file.File.create) + self.assert_not_wrapped(openai.api_resources.file.File.retrieve) + self.assert_not_wrapped(openai.api_resources.file.File.list) + self.assert_not_wrapped(openai.api_resources.file.File.delete) + self.assert_not_wrapped(openai.api_resources.file.File.aretrieve_content) + self.assert_not_wrapped(openai.api_resources.file.File.acreate) + self.assert_not_wrapped(openai.api_resources.file.File.aretrieve) + self.assert_not_wrapped(openai.api_resources.file.File.alist) + self.assert_not_wrapped(openai.api_resources.file.File.adelete) def assert_not_module_double_patched(self, openai): - pass + if OPENAI_VERSION >= (1, 0, 0): + if OPENAI_VERSION >= (1, 8, 0): + self.assert_not_double_wrapped(openai._base_client.SyncAPIClient._process_response) + self.assert_not_double_wrapped(openai._base_client.AsyncAPIClient._process_response) + else: + self.assert_not_double_wrapped(openai._base_client.BaseClient._process_response) + self.assert_not_double_wrapped(openai.OpenAI.__init__) + self.assert_not_double_wrapped(openai.AsyncOpenAI.__init__) + self.assert_not_double_wrapped(openai.AzureOpenAI.__init__) + self.assert_not_double_wrapped(openai.AsyncAzureOpenAI.__init__) + self.assert_not_double_wrapped(openai.resources.models.Models.list) + self.assert_not_double_wrapped(openai.resources.models.Models.retrieve) + self.assert_not_double_wrapped(openai.resources.models.Models.delete) + self.assert_not_double_wrapped(openai.resources.models.AsyncModels.list) + self.assert_not_double_wrapped(openai.resources.models.AsyncModels.retrieve) + self.assert_not_double_wrapped(openai.resources.models.AsyncModels.delete) + self.assert_not_double_wrapped(openai.resources.completions.Completions.create) + self.assert_not_double_wrapped(openai.resources.chat.Completions.create) + self.assert_not_double_wrapped(openai.resources.completions.AsyncCompletions.create) + self.assert_not_double_wrapped(openai.resources.chat.AsyncCompletions.create) + self.assert_not_double_wrapped(openai.resources.images.Images.generate) + self.assert_not_double_wrapped(openai.resources.images.Images.edit) + self.assert_not_double_wrapped(openai.resources.images.Images.create_variation) + self.assert_not_double_wrapped(openai.resources.images.AsyncImages.generate) + self.assert_not_double_wrapped(openai.resources.images.AsyncImages.edit) + self.assert_not_double_wrapped(openai.resources.images.AsyncImages.create_variation) + self.assert_not_double_wrapped(openai.resources.audio.Transcriptions.create) + self.assert_not_double_wrapped(openai.resources.audio.Translations.create) + self.assert_not_double_wrapped(openai.resources.audio.AsyncTranscriptions.create) + self.assert_not_double_wrapped(openai.resources.audio.AsyncTranslations.create) + self.assert_not_double_wrapped(openai.resources.embeddings.Embeddings.create) + self.assert_not_double_wrapped(openai.resources.moderations.Moderations.create) + self.assert_not_double_wrapped(openai.resources.embeddings.AsyncEmbeddings.create) + self.assert_not_double_wrapped(openai.resources.moderations.AsyncModerations.create) + self.assert_not_double_wrapped(openai.resources.files.Files.create) + self.assert_not_double_wrapped(openai.resources.files.Files.retrieve) + self.assert_not_double_wrapped(openai.resources.files.Files.list) + self.assert_not_double_wrapped(openai.resources.files.Files.delete) + self.assert_not_double_wrapped(openai.resources.files.Files.retrieve_content) + self.assert_not_double_wrapped(openai.resources.files.AsyncFiles.create) + self.assert_not_double_wrapped(openai.resources.files.AsyncFiles.retrieve) + self.assert_not_double_wrapped(openai.resources.files.AsyncFiles.list) + self.assert_not_double_wrapped(openai.resources.files.AsyncFiles.delete) + self.assert_not_double_wrapped(openai.resources.files.AsyncFiles.retrieve_content) + + else: + self.assert_not_double_wrapped(openai.api_resources.completion.Completion.create) + self.assert_not_double_wrapped(openai.api_resources.completion.Completion.acreate) + self.assert_not_double_wrapped(openai.api_requestor._make_session) + self.assert_not_double_wrapped(openai.util.convert_to_openai_object) + self.assert_not_double_wrapped(openai.api_resources.embedding.Embedding.create) + self.assert_not_double_wrapped(openai.api_resources.embedding.Embedding.acreate) + if hasattr(openai, "Model"): + self.assert_not_double_wrapped(openai.api_resources.model.Model.list) + self.assert_not_double_wrapped(openai.api_resources.model.Model.retrieve) + self.assert_not_double_wrapped(openai.api_resources.model.Model.delete) + self.assert_not_double_wrapped(openai.api_resources.model.Model.alist) + self.assert_not_double_wrapped(openai.api_resources.model.Model.aretrieve) + self.assert_not_double_wrapped(openai.api_resources.model.Model.adelete) + if hasattr(openai, "ChatCompletion"): + self.assert_not_double_wrapped(openai.api_resources.chat_completion.ChatCompletion.create) + self.assert_not_double_wrapped(openai.api_resources.chat_completion.ChatCompletion.acreate) + if hasattr(openai, "Image"): + self.assert_not_double_wrapped(openai.api_resources.image.Image.create) + self.assert_not_double_wrapped(openai.api_resources.image.Image.acreate) + self.assert_not_double_wrapped(openai.api_resources.image.Image.create_edit) + self.assert_not_double_wrapped(openai.api_resources.image.Image.acreate_edit) + self.assert_not_double_wrapped(openai.api_resources.image.Image.create_variation) + self.assert_not_double_wrapped(openai.api_resources.image.Image.acreate_variation) + if hasattr(openai, "Audio"): + self.assert_not_double_wrapped(openai.api_resources.audio.Audio.transcribe) + self.assert_not_double_wrapped(openai.api_resources.audio.Audio.atranscribe) + self.assert_not_double_wrapped(openai.api_resources.audio.Audio.translate) + self.assert_not_double_wrapped(openai.api_resources.audio.Audio.atranslate) + if hasattr(openai, "Moderation"): + self.assert_not_double_wrapped(openai.api_resources.moderation.Moderation.create) + self.assert_not_double_wrapped(openai.api_resources.moderation.Moderation.acreate) + if hasattr(openai, "File"): + self.assert_not_double_wrapped(openai.api_resources.file.File.create) + self.assert_not_double_wrapped(openai.api_resources.file.File.retrieve) + self.assert_not_double_wrapped(openai.api_resources.file.File.list) + self.assert_not_double_wrapped(openai.api_resources.file.File.delete) + self.assert_not_double_wrapped(openai.api_resources.file.File.aretrieve_content) + self.assert_not_double_wrapped(openai.api_resources.file.File.acreate) + self.assert_not_double_wrapped(openai.api_resources.file.File.aretrieve) + self.assert_not_double_wrapped(openai.api_resources.file.File.alist) + self.assert_not_double_wrapped(openai.api_resources.file.File.adelete) diff --git a/tests/contrib/openai/test_openai_v0.py b/tests/contrib/openai/test_openai_v0.py index 3fa262e8a4a..0a618b4bffc 100644 --- a/tests/contrib/openai/test_openai_v0.py +++ b/tests/contrib/openai/test_openai_v0.py @@ -9,9 +9,7 @@ import pytest import ddtrace -from ddtrace import patch from ddtrace.contrib.internal.openai.utils import _est_tokens -from ddtrace.contrib.trace_utils import iswrapped from ddtrace.internal.utils.version import parse_version from tests.contrib.openai.utils import chat_completion_custom_functions from tests.contrib.openai.utils import chat_completion_input_description @@ -41,42 +39,6 @@ def test_config(ddtrace_config_openai, mock_tracer, openai): assert ddtrace.config.openai.metrics_enabled is ddtrace_config_openai["metrics_enabled"] -def test_patching(openai): - """Ensure that the correct objects are patched and not double patched.""" - - # for some reason these can't be specified as the real python objects... - # no clue why (eg. openai.Completion.create doesn't work) - methods = [ - (openai.Completion, "create"), - (openai.api_resources.completion.Completion, "create"), - (openai.Completion, "acreate"), - (openai.api_resources.completion.Completion, "acreate"), - (openai.api_requestor, "_make_session"), - (openai.util, "convert_to_openai_object"), - (openai.Embedding, "create"), - (openai.Embedding, "acreate"), - ] - if hasattr(openai, "ChatCompletion"): - methods += [ - (openai.ChatCompletion, "create"), - (openai.api_resources.chat_completion.ChatCompletion, "create"), - (openai.ChatCompletion, "acreate"), - (openai.api_resources.chat_completion.ChatCompletion, "acreate"), - ] - - for m in methods: - assert not iswrapped(getattr(m[0], m[1])) - - patch(openai=True) - for m in methods: - assert iswrapped(getattr(m[0], m[1])) - - # Ensure double patching does not occur - patch(openai=True) - for m in methods: - assert not iswrapped(getattr(m[0], m[1]).__dd_wrapped__) - - @pytest.mark.parametrize("api_key_in_env", [True, False]) def test_model_list(api_key_in_env, request_api_key, openai, openai_vcr, mock_metrics, snapshot_tracer): with snapshot_context( diff --git a/tests/contrib/openai/test_openai_v1.py b/tests/contrib/openai/test_openai_v1.py index 918d3eadae9..6468c696d0f 100644 --- a/tests/contrib/openai/test_openai_v1.py +++ b/tests/contrib/openai/test_openai_v1.py @@ -5,9 +5,7 @@ import pytest import ddtrace -from ddtrace import patch from ddtrace.contrib.internal.openai.utils import _est_tokens -from ddtrace.contrib.trace_utils import iswrapped from ddtrace.internal.utils.version import parse_version from tests.contrib.openai.utils import chat_completion_custom_functions from tests.contrib.openai.utils import chat_completion_input_description @@ -37,56 +35,6 @@ def test_config(ddtrace_config_openai, mock_tracer, openai): assert ddtrace.config.openai.metrics_enabled is ddtrace_config_openai["metrics_enabled"] -def test_patching(openai): - """Ensure that the correct objects are patched and not double patched.""" - methods = [ - (openai.resources.completions.Completions, "create"), - (openai.resources.completions.AsyncCompletions, "create"), - (openai.resources.chat.Completions, "create"), - (openai.resources.chat.AsyncCompletions, "create"), - (openai.resources.embeddings.Embeddings, "create"), - (openai.resources.embeddings.AsyncEmbeddings, "create"), - (openai.resources.models.Models, "list"), - (openai.resources.models.Models, "retrieve"), - (openai.resources.models.AsyncModels, "list"), - (openai.resources.models.AsyncModels, "retrieve"), - (openai.resources.images.Images, "generate"), - (openai.resources.images.Images, "edit"), - (openai.resources.images.Images, "create_variation"), - (openai.resources.images.AsyncImages, "generate"), - (openai.resources.images.AsyncImages, "edit"), - (openai.resources.images.AsyncImages, "create_variation"), - (openai.resources.audio.Transcriptions, "create"), - (openai.resources.audio.AsyncTranscriptions, "create"), - (openai.resources.audio.Translations, "create"), - (openai.resources.audio.AsyncTranslations, "create"), - (openai.resources.moderations.Moderations, "create"), - (openai.resources.moderations.AsyncModerations, "create"), - (openai.resources.files.Files, "create"), - (openai.resources.files.Files, "retrieve"), - (openai.resources.files.Files, "list"), - (openai.resources.files.Files, "delete"), - (openai.resources.files.Files, "retrieve_content"), - (openai.resources.files.AsyncFiles, "create"), - (openai.resources.files.AsyncFiles, "retrieve"), - (openai.resources.files.AsyncFiles, "list"), - (openai.resources.files.AsyncFiles, "delete"), - (openai.resources.files.AsyncFiles, "retrieve_content"), - ] - - for m in methods: - assert not iswrapped(getattr(m[0], m[1])) - - patch(openai=True) - for m in methods: - assert iswrapped(getattr(m[0], m[1])) - - # Ensure double patching does not occur - patch(openai=True) - for m in methods: - assert not iswrapped(getattr(m[0], m[1]).__dd_wrapped__) - - @pytest.mark.parametrize("api_key_in_env", [True, False]) def test_model_list(api_key_in_env, request_api_key, openai, openai_vcr, mock_metrics, snapshot_tracer): with snapshot_context( From 14b73fa4660c87c59a170c17e50c3794c107ffcc Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Wed, 22 Jan 2025 12:12:50 -0500 Subject: [PATCH 02/11] Update openai tests for supported versions --- .riot/requirements/107d8f2.txt | 54 ++++++++++++++++++ .riot/requirements/129c849.txt | 50 ++++++++++++++++ .riot/requirements/130158f.txt | 48 ++++++++++++++++ .riot/requirements/13804af.txt | 57 ------------------- .riot/requirements/13fec34.txt | 49 ---------------- .riot/requirements/179818d.txt | 52 +++++++++++++++++ .riot/requirements/181216c.txt | 52 ----------------- .riot/requirements/18d588e.txt | 50 ++++++++++++++++ .riot/requirements/18de44f.txt | 52 +++++++++++++++++ .riot/requirements/1ad89c5.txt | 50 ++++++++++++++++ .riot/requirements/1bfbfdd.txt | 50 ++++++++++++++++ .../requirements/{1db5311.txt => 1e6bd37.txt} | 47 +++++++-------- .riot/requirements/1ec15f5.txt | 57 ------------------- .riot/requirements/1ee49b9.txt | 53 ----------------- .riot/requirements/2634bf7.txt | 48 ++++++++++++++++ .riot/requirements/35ce786.txt | 55 ------------------ .riot/requirements/3db7151.txt | 54 ++++++++++++++++++ .riot/requirements/4a85f6d.txt | 50 ++++++++++++++++ .riot/requirements/4d27459.txt | 48 ++++++++++++++++ .riot/requirements/530c983.txt | 52 +++++++++++++++++ .riot/requirements/5da4fd8.txt | 49 ---------------- .riot/requirements/87a1fff.txt | 53 ----------------- .../requirements/{84ec59a.txt => 900aca5.txt} | 45 ++++++++------- .riot/requirements/b5d5a35.txt | 52 +++++++++++++++++ .riot/requirements/c74f6e0.txt | 51 ----------------- .riot/requirements/cd2e4ea.txt | 53 ----------------- .riot/requirements/f1c37b1.txt | 51 ----------------- .riot/requirements/f7c30a0.txt | 51 ----------------- riotfile.py | 7 ++- 29 files changed, 761 insertions(+), 679 deletions(-) create mode 100644 .riot/requirements/107d8f2.txt create mode 100644 .riot/requirements/129c849.txt create mode 100644 .riot/requirements/130158f.txt delete mode 100644 .riot/requirements/13804af.txt delete mode 100644 .riot/requirements/13fec34.txt create mode 100644 .riot/requirements/179818d.txt delete mode 100644 .riot/requirements/181216c.txt create mode 100644 .riot/requirements/18d588e.txt create mode 100644 .riot/requirements/18de44f.txt create mode 100644 .riot/requirements/1ad89c5.txt create mode 100644 .riot/requirements/1bfbfdd.txt rename .riot/requirements/{1db5311.txt => 1e6bd37.txt} (55%) delete mode 100644 .riot/requirements/1ec15f5.txt delete mode 100644 .riot/requirements/1ee49b9.txt create mode 100644 .riot/requirements/2634bf7.txt delete mode 100644 .riot/requirements/35ce786.txt create mode 100644 .riot/requirements/3db7151.txt create mode 100644 .riot/requirements/4a85f6d.txt create mode 100644 .riot/requirements/4d27459.txt create mode 100644 .riot/requirements/530c983.txt delete mode 100644 .riot/requirements/5da4fd8.txt delete mode 100644 .riot/requirements/87a1fff.txt rename .riot/requirements/{84ec59a.txt => 900aca5.txt} (57%) create mode 100644 .riot/requirements/b5d5a35.txt delete mode 100644 .riot/requirements/c74f6e0.txt delete mode 100644 .riot/requirements/cd2e4ea.txt delete mode 100644 .riot/requirements/f1c37b1.txt delete mode 100644 .riot/requirements/f7c30a0.txt diff --git a/.riot/requirements/107d8f2.txt b/.riot/requirements/107d8f2.txt new file mode 100644 index 00000000000..7bed129ddaf --- /dev/null +++ b/.riot/requirements/107d8f2.txt @@ -0,0 +1,54 @@ +# +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: +# +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/107d8f2.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +coverage[toml]==7.6.10 +distro==1.9.0 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +hypothesis==6.45.0 +idna==3.10 +importlib-metadata==8.6.1 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.1.0 +numpy==2.0.2 +openai[datalib,embeddings]==1.30.1 +opentracing==2.4.0 +packaging==24.2 +pandas==2.2.3 +pandas-stubs==2.2.2.240807 +pillow==9.5.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +pyyaml==6.0.2 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tomli==2.2.1 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 +typing-extensions==4.12.2 +tzdata==2025.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 +zipp==3.21.0 diff --git a/.riot/requirements/129c849.txt b/.riot/requirements/129c849.txt new file mode 100644 index 00000000000..1a2dded5bb8 --- /dev/null +++ b/.riot/requirements/129c849.txt @@ -0,0 +1,50 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --no-annotate .riot/requirements/129c849.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +coverage[toml]==7.6.10 +distro==1.9.0 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.1.0 +numpy==2.2.2 +openai[datalib,embeddings]==1.30.1 +opentracing==2.4.0 +packaging==24.2 +pandas==2.2.3 +pandas-stubs==2.2.3.241126 +pillow==9.5.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +pyyaml==6.0.2 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 +typing-extensions==4.12.2 +tzdata==2025.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/130158f.txt b/.riot/requirements/130158f.txt new file mode 100644 index 00000000000..037c7010f33 --- /dev/null +++ b/.riot/requirements/130158f.txt @@ -0,0 +1,48 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --no-annotate .riot/requirements/130158f.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +charset-normalizer==3.4.1 +coverage[toml]==7.6.10 +distro==1.9.0 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +jiter==0.8.2 +mock==5.1.0 +multidict==6.1.0 +openai==1.60.0 +opentracing==2.4.0 +packaging==24.2 +pillow==11.1.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +pyyaml==6.0.2 +regex==2024.11.6 +requests==2.32.3 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tiktoken==0.8.0 +tqdm==4.67.1 +typing-extensions==4.12.2 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/13804af.txt b/.riot/requirements/13804af.txt deleted file mode 100644 index 7035a764386..00000000000 --- a/.riot/requirements/13804af.txt +++ /dev/null @@ -1,57 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.8 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/13804af.in -# -annotated-types==0.7.0 -anyio==4.4.0 -attrs==24.2.0 -certifi==2024.7.4 -charset-normalizer==3.3.2 -coverage[toml]==7.6.1 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -importlib-metadata==8.4.0 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==1.24.4 -openai[datalib]==1.30.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.0.3 -pandas-stubs==2.0.3.230814 -pillow==10.1.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -regex==2024.7.24 -requests==2.32.3 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tiktoken==0.7.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.20.1 diff --git a/.riot/requirements/13fec34.txt b/.riot/requirements/13fec34.txt deleted file mode 100644 index 8858506f793..00000000000 --- a/.riot/requirements/13fec34.txt +++ /dev/null @@ -1,49 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/13fec34.in -# -annotated-types==0.7.0 -anyio==3.7.1 -attrs==24.2.0 -certifi==2024.7.4 -coverage[toml]==7.6.1 -distro==1.9.0 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.1.0 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==9.5.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 diff --git a/.riot/requirements/179818d.txt b/.riot/requirements/179818d.txt new file mode 100644 index 00000000000..bc6cd83028d --- /dev/null +++ b/.riot/requirements/179818d.txt @@ -0,0 +1,52 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --no-annotate .riot/requirements/179818d.in +# +annotated-types==0.7.0 +anyio==3.7.1 +attrs==24.3.0 +certifi==2024.12.14 +coverage[toml]==7.6.10 +distro==1.9.0 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.1.0 +numpy==2.2.2 +openai[datalib,embeddings]==1.1.1 +opentracing==2.4.0 +packaging==24.2 +pandas==2.2.3 +pandas-stubs==2.2.3.241126 +pillow==9.5.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +pyyaml==6.0.2 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tomli==2.2.1 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 +typing-extensions==4.12.2 +tzdata==2025.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/181216c.txt b/.riot/requirements/181216c.txt deleted file mode 100644 index ac739930363..00000000000 --- a/.riot/requirements/181216c.txt +++ /dev/null @@ -1,52 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.7 -# by the following command: -# -# pip-compile --allow-unsafe --config=pyproject.toml --no-annotate --resolver=backtracking .riot/requirements/181216c.in -# -annotated-types==0.5.0 -anyio==3.7.1 -attrs==24.2.0 -cached-property==1.5.2 -certifi==2024.7.4 -coverage[toml]==7.2.7 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==0.17.3 -httpx==0.24.1 -hypothesis==6.45.0 -idna==3.8 -importlib-metadata==6.7.0 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==1.21.6 -openai[datalib,embeddings]==1.30.1 -opentracing==2.4.0 -packaging==24.0 -pandas==1.3.5 -pandas-stubs==1.2.0.62 -pillow==9.5.0 -pluggy==1.2.0 -pydantic==2.5.3 -pydantic-core==2.14.6 -pytest==7.4.4 -pytest-asyncio==0.21.1 -pytest-cov==4.1.0 -pytest-mock==3.11.1 -pytest-randomly==3.12.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.1 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.0.1 -tqdm==4.66.5 -typing-extensions==4.7.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.15.0 diff --git a/.riot/requirements/18d588e.txt b/.riot/requirements/18d588e.txt new file mode 100644 index 00000000000..82bcdf7626f --- /dev/null +++ b/.riot/requirements/18d588e.txt @@ -0,0 +1,50 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/18d588e.in +# +annotated-types==0.7.0 +anyio==3.7.1 +attrs==24.3.0 +certifi==2024.12.14 +coverage[toml]==7.6.10 +distro==1.9.0 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.1.0 +numpy==2.2.2 +openai[datalib,embeddings]==1.1.1 +opentracing==2.4.0 +packaging==24.2 +pandas==2.2.3 +pandas-stubs==2.2.3.241126 +pillow==9.5.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +pyyaml==6.0.2 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 +typing-extensions==4.12.2 +tzdata==2025.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/18de44f.txt b/.riot/requirements/18de44f.txt new file mode 100644 index 00000000000..702b980c641 --- /dev/null +++ b/.riot/requirements/18de44f.txt @@ -0,0 +1,52 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/18de44f.in +# +annotated-types==0.7.0 +anyio==4.5.2 +attrs==24.3.0 +certifi==2024.12.14 +charset-normalizer==3.4.1 +coverage[toml]==7.6.1 +distro==1.9.0 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +hypothesis==6.45.0 +idna==3.10 +importlib-metadata==8.5.0 +iniconfig==2.0.0 +jiter==0.8.2 +mock==5.1.0 +multidict==6.1.0 +openai==1.60.0 +opentracing==2.4.0 +packaging==24.2 +pillow==10.4.0 +pluggy==1.5.0 +propcache==0.2.0 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==5.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.15.0 +pyyaml==6.0.2 +regex==2024.11.6 +requests==2.32.3 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tiktoken==0.7.0 +tomli==2.2.1 +tqdm==4.67.1 +typing-extensions==4.12.2 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.15.2 +zipp==3.20.2 diff --git a/.riot/requirements/1ad89c5.txt b/.riot/requirements/1ad89c5.txt new file mode 100644 index 00000000000..b10206e12d9 --- /dev/null +++ b/.riot/requirements/1ad89c5.txt @@ -0,0 +1,50 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --no-annotate .riot/requirements/1ad89c5.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +charset-normalizer==3.4.1 +coverage[toml]==7.6.10 +distro==1.9.0 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +jiter==0.8.2 +mock==5.1.0 +multidict==6.1.0 +openai==1.60.0 +opentracing==2.4.0 +packaging==24.2 +pillow==11.1.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +pyyaml==6.0.2 +regex==2024.11.6 +requests==2.32.3 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tiktoken==0.8.0 +tomli==2.2.1 +tqdm==4.67.1 +typing-extensions==4.12.2 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/1bfbfdd.txt b/.riot/requirements/1bfbfdd.txt new file mode 100644 index 00000000000..42907f03519 --- /dev/null +++ b/.riot/requirements/1bfbfdd.txt @@ -0,0 +1,50 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --no-annotate .riot/requirements/1bfbfdd.in +# +annotated-types==0.7.0 +anyio==3.7.1 +attrs==24.3.0 +certifi==2024.12.14 +coverage[toml]==7.6.10 +distro==1.9.0 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.1.0 +numpy==2.2.2 +openai[datalib,embeddings]==1.1.1 +opentracing==2.4.0 +packaging==24.2 +pandas==2.2.3 +pandas-stubs==2.2.3.241126 +pillow==9.5.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +pyyaml==6.0.2 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 +typing-extensions==4.12.2 +tzdata==2025.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/1db5311.txt b/.riot/requirements/1e6bd37.txt similarity index 55% rename from .riot/requirements/1db5311.txt rename to .riot/requirements/1e6bd37.txt index c29bc9bdb8f..11bb5871c14 100644 --- a/.riot/requirements/1db5311.txt +++ b/.riot/requirements/1e6bd37.txt @@ -2,52 +2,53 @@ # This file is autogenerated by pip-compile with Python 3.8 # by the following command: # -# pip-compile --allow-unsafe --no-annotate .riot/requirements/1db5311.in +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/1e6bd37.in # annotated-types==0.7.0 -anyio==4.4.0 -attrs==24.2.0 -certifi==2024.7.4 +anyio==4.5.2 +attrs==24.3.0 +certifi==2024.12.14 coverage[toml]==7.6.1 distro==1.9.0 exceptiongroup==1.2.2 h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 +httpcore==1.0.7 +httpx==0.27.2 hypothesis==6.45.0 -idna==3.8 -importlib-metadata==8.4.0 +idna==3.10 +importlib-metadata==8.5.0 iniconfig==2.0.0 mock==5.1.0 -multidict==6.0.5 +multidict==6.1.0 numpy==1.24.4 openai[datalib,embeddings]==1.30.1 opentracing==2.4.0 -packaging==24.1 +packaging==24.2 pandas==2.0.3 pandas-stubs==2.0.3.230814 pillow==9.5.0 pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 +propcache==0.2.0 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 pytest-asyncio==0.21.1 pytest-cov==5.0.0 pytest-mock==3.14.0 pytest-randomly==3.15.0 python-dateutil==2.9.0.post0 -pytz==2024.1 +pytz==2024.2 pyyaml==6.0.2 -six==1.16.0 +six==1.17.0 sniffio==1.3.1 sortedcontainers==2.4.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 +tomli==2.2.1 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 +tzdata==2025.1 +urllib3==1.26.20 vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.20.1 +wrapt==1.17.2 +yarl==1.15.2 +zipp==3.20.2 diff --git a/.riot/requirements/1ec15f5.txt b/.riot/requirements/1ec15f5.txt deleted file mode 100644 index b4479a2fb39..00000000000 --- a/.riot/requirements/1ec15f5.txt +++ /dev/null @@ -1,57 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/1ec15f5.in -# -annotated-types==0.7.0 -anyio==4.4.0 -attrs==24.2.0 -certifi==2024.7.4 -charset-normalizer==3.3.2 -coverage[toml]==7.6.1 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -importlib-metadata==8.4.0 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.0.1 -openai[datalib]==1.30.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==10.1.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -regex==2024.7.24 -requests==2.32.3 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tiktoken==0.7.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.20.1 diff --git a/.riot/requirements/1ee49b9.txt b/.riot/requirements/1ee49b9.txt deleted file mode 100644 index f170e2885c4..00000000000 --- a/.riot/requirements/1ee49b9.txt +++ /dev/null @@ -1,53 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/1ee49b9.in -# -annotated-types==0.7.0 -anyio==4.4.0 -attrs==24.2.0 -certifi==2024.7.4 -charset-normalizer==3.3.2 -coverage[toml]==7.6.1 -distro==1.9.0 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.1.0 -openai[datalib]==1.30.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==10.1.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -regex==2024.7.24 -requests==2.32.3 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tiktoken==0.7.0 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 diff --git a/.riot/requirements/2634bf7.txt b/.riot/requirements/2634bf7.txt new file mode 100644 index 00000000000..0000f6e28ff --- /dev/null +++ b/.riot/requirements/2634bf7.txt @@ -0,0 +1,48 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/2634bf7.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +charset-normalizer==3.4.1 +coverage[toml]==7.6.10 +distro==1.9.0 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +jiter==0.8.2 +mock==5.1.0 +multidict==6.1.0 +openai==1.60.0 +opentracing==2.4.0 +packaging==24.2 +pillow==11.1.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +pyyaml==6.0.2 +regex==2024.11.6 +requests==2.32.3 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tiktoken==0.8.0 +tqdm==4.67.1 +typing-extensions==4.12.2 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/35ce786.txt b/.riot/requirements/35ce786.txt deleted file mode 100644 index 3489155be91..00000000000 --- a/.riot/requirements/35ce786.txt +++ /dev/null @@ -1,55 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/35ce786.in -# -annotated-types==0.7.0 -anyio==4.4.0 -attrs==24.2.0 -certifi==2024.7.4 -charset-normalizer==3.3.2 -coverage[toml]==7.6.1 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.1.0 -openai[datalib]==1.30.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==10.1.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -regex==2024.7.24 -requests==2.32.3 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tiktoken==0.7.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 diff --git a/.riot/requirements/3db7151.txt b/.riot/requirements/3db7151.txt new file mode 100644 index 00000000000..dcd3b85a214 --- /dev/null +++ b/.riot/requirements/3db7151.txt @@ -0,0 +1,54 @@ +# +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: +# +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/3db7151.in +# +annotated-types==0.7.0 +anyio==3.7.1 +attrs==24.3.0 +certifi==2024.12.14 +coverage[toml]==7.6.10 +distro==1.9.0 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +hypothesis==6.45.0 +idna==3.10 +importlib-metadata==8.6.1 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.1.0 +numpy==2.0.2 +openai[datalib,embeddings]==1.1.1 +opentracing==2.4.0 +packaging==24.2 +pandas==2.2.3 +pandas-stubs==2.2.2.240807 +pillow==9.5.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +pyyaml==6.0.2 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tomli==2.2.1 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 +typing-extensions==4.12.2 +tzdata==2025.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 +zipp==3.21.0 diff --git a/.riot/requirements/4a85f6d.txt b/.riot/requirements/4a85f6d.txt new file mode 100644 index 00000000000..41953c69178 --- /dev/null +++ b/.riot/requirements/4a85f6d.txt @@ -0,0 +1,50 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/4a85f6d.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +coverage[toml]==7.6.10 +distro==1.9.0 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.1.0 +numpy==2.2.2 +openai[datalib,embeddings]==1.30.1 +opentracing==2.4.0 +packaging==24.2 +pandas==2.2.3 +pandas-stubs==2.2.3.241126 +pillow==9.5.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +pyyaml==6.0.2 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 +typing-extensions==4.12.2 +tzdata==2025.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/4d27459.txt b/.riot/requirements/4d27459.txt new file mode 100644 index 00000000000..630c81558f3 --- /dev/null +++ b/.riot/requirements/4d27459.txt @@ -0,0 +1,48 @@ +# +# This file is autogenerated by pip-compile with Python 3.13 +# by the following command: +# +# pip-compile --no-annotate .riot/requirements/4d27459.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +charset-normalizer==3.4.1 +coverage[toml]==7.6.10 +distro==1.9.0 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +jiter==0.8.2 +mock==5.1.0 +multidict==6.1.0 +openai==1.60.0 +opentracing==2.4.0 +packaging==24.2 +pillow==11.1.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +pyyaml==6.0.2 +regex==2024.11.6 +requests==2.32.3 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tiktoken==0.8.0 +tqdm==4.67.1 +typing-extensions==4.12.2 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/530c983.txt b/.riot/requirements/530c983.txt new file mode 100644 index 00000000000..c07f9a6b918 --- /dev/null +++ b/.riot/requirements/530c983.txt @@ -0,0 +1,52 @@ +# +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: +# +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/530c983.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +charset-normalizer==3.4.1 +coverage[toml]==7.6.10 +distro==1.9.0 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +hypothesis==6.45.0 +idna==3.10 +importlib-metadata==8.6.1 +iniconfig==2.0.0 +jiter==0.8.2 +mock==5.1.0 +multidict==6.1.0 +openai==1.60.0 +opentracing==2.4.0 +packaging==24.2 +pillow==11.1.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +pyyaml==6.0.2 +regex==2024.11.6 +requests==2.32.3 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tiktoken==0.8.0 +tomli==2.2.1 +tqdm==4.67.1 +typing-extensions==4.12.2 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 +zipp==3.21.0 diff --git a/.riot/requirements/5da4fd8.txt b/.riot/requirements/5da4fd8.txt deleted file mode 100644 index a700b91bf81..00000000000 --- a/.riot/requirements/5da4fd8.txt +++ /dev/null @@ -1,49 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/5da4fd8.in -# -annotated-types==0.7.0 -anyio==4.4.0 -attrs==24.2.0 -certifi==2024.7.4 -coverage[toml]==7.6.1 -distro==1.9.0 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.1.0 -openai[datalib,embeddings]==1.30.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==9.5.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 diff --git a/.riot/requirements/87a1fff.txt b/.riot/requirements/87a1fff.txt deleted file mode 100644 index b85e76cdd56..00000000000 --- a/.riot/requirements/87a1fff.txt +++ /dev/null @@ -1,53 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/87a1fff.in -# -annotated-types==0.7.0 -anyio==4.4.0 -attrs==24.2.0 -certifi==2024.7.4 -coverage[toml]==7.6.1 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -importlib-metadata==8.4.0 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.0.1 -openai[datalib,embeddings]==1.30.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==9.5.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.20.1 diff --git a/.riot/requirements/84ec59a.txt b/.riot/requirements/900aca5.txt similarity index 57% rename from .riot/requirements/84ec59a.txt rename to .riot/requirements/900aca5.txt index 9b079cf3a38..5aed01fdb62 100644 --- a/.riot/requirements/84ec59a.txt +++ b/.riot/requirements/900aca5.txt @@ -2,52 +2,53 @@ # This file is autogenerated by pip-compile with Python 3.8 # by the following command: # -# pip-compile --allow-unsafe --no-annotate .riot/requirements/84ec59a.in +# pip-compile --no-annotate --resolver=backtracking .riot/requirements/900aca5.in # annotated-types==0.7.0 anyio==3.7.1 -attrs==24.2.0 -certifi==2024.7.4 +attrs==24.3.0 +certifi==2024.12.14 coverage[toml]==7.6.1 distro==1.9.0 exceptiongroup==1.2.2 h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 +httpcore==1.0.7 +httpx==0.27.2 hypothesis==6.45.0 -idna==3.8 -importlib-metadata==8.4.0 +idna==3.10 +importlib-metadata==8.5.0 iniconfig==2.0.0 mock==5.1.0 -multidict==6.0.5 +multidict==6.1.0 numpy==1.24.4 openai[datalib,embeddings]==1.1.1 opentracing==2.4.0 -packaging==24.1 +packaging==24.2 pandas==2.0.3 pandas-stubs==2.0.3.230814 pillow==9.5.0 pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 +propcache==0.2.0 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 pytest-asyncio==0.21.1 pytest-cov==5.0.0 pytest-mock==3.14.0 pytest-randomly==3.15.0 python-dateutil==2.9.0.post0 -pytz==2024.1 +pytz==2024.2 pyyaml==6.0.2 -six==1.16.0 +six==1.17.0 sniffio==1.3.1 sortedcontainers==2.4.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 +tomli==2.2.1 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 +tzdata==2025.1 +urllib3==1.26.20 vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.20.1 +wrapt==1.17.2 +yarl==1.15.2 +zipp==3.20.2 diff --git a/.riot/requirements/b5d5a35.txt b/.riot/requirements/b5d5a35.txt new file mode 100644 index 00000000000..7838b7abd2c --- /dev/null +++ b/.riot/requirements/b5d5a35.txt @@ -0,0 +1,52 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --no-annotate .riot/requirements/b5d5a35.in +# +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +coverage[toml]==7.6.10 +distro==1.9.0 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +hypothesis==6.45.0 +idna==3.10 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.1.0 +numpy==2.2.2 +openai[datalib,embeddings]==1.30.1 +opentracing==2.4.0 +packaging==24.2 +pandas==2.2.3 +pandas-stubs==2.2.3.241126 +pillow==9.5.0 +pluggy==1.5.0 +propcache==0.2.1 +pydantic==2.10.5 +pydantic-core==2.27.2 +pytest==8.3.4 +pytest-asyncio==0.21.1 +pytest-cov==6.0.0 +pytest-mock==3.14.0 +pytest-randomly==3.16.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +pyyaml==6.0.2 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tomli==2.2.1 +tqdm==4.67.1 +types-pytz==2024.2.0.20241221 +typing-extensions==4.12.2 +tzdata==2025.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.17.2 +yarl==1.18.3 diff --git a/.riot/requirements/c74f6e0.txt b/.riot/requirements/c74f6e0.txt deleted file mode 100644 index 63345853661..00000000000 --- a/.riot/requirements/c74f6e0.txt +++ /dev/null @@ -1,51 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/c74f6e0.in -# -annotated-types==0.7.0 -anyio==4.4.0 -attrs==24.2.0 -certifi==2024.7.4 -coverage[toml]==7.6.1 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.1.0 -openai[datalib,embeddings]==1.30.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==9.5.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 diff --git a/.riot/requirements/cd2e4ea.txt b/.riot/requirements/cd2e4ea.txt deleted file mode 100644 index 24353dafa0c..00000000000 --- a/.riot/requirements/cd2e4ea.txt +++ /dev/null @@ -1,53 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/cd2e4ea.in -# -annotated-types==0.7.0 -anyio==3.7.1 -attrs==24.2.0 -certifi==2024.7.4 -coverage[toml]==7.6.1 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -importlib-metadata==8.4.0 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.0.1 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==9.5.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.20.1 diff --git a/.riot/requirements/f1c37b1.txt b/.riot/requirements/f1c37b1.txt deleted file mode 100644 index 4da5078a988..00000000000 --- a/.riot/requirements/f1c37b1.txt +++ /dev/null @@ -1,51 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/f1c37b1.in -# -annotated-types==0.7.0 -anyio==3.7.1 -attrs==24.2.0 -certifi==2024.7.4 -coverage[toml]==7.6.1 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.5 -httpx==0.27.0 -hypothesis==6.45.0 -idna==3.8 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==2.1.0 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.1 -pandas==2.2.2 -pandas-stubs==2.2.2.240807 -pillow==9.5.0 -pluggy==1.5.0 -pydantic==2.8.2 -pydantic-core==2.20.1 -pytest==8.3.2 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.2 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.0.1 -tqdm==4.66.5 -types-pytz==2024.1.0.20240417 -typing-extensions==4.12.2 -tzdata==2024.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 diff --git a/.riot/requirements/f7c30a0.txt b/.riot/requirements/f7c30a0.txt deleted file mode 100644 index 3e4716aede1..00000000000 --- a/.riot/requirements/f7c30a0.txt +++ /dev/null @@ -1,51 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.7 -# by the following command: -# -# pip-compile --allow-unsafe --config=pyproject.toml --no-annotate --resolver=backtracking .riot/requirements/f7c30a0.in -# -annotated-types==0.5.0 -anyio==3.7.1 -attrs==24.2.0 -certifi==2024.7.4 -coverage[toml]==7.2.7 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==0.17.3 -httpx==0.24.1 -hypothesis==6.45.0 -idna==3.8 -importlib-metadata==6.7.0 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.0.5 -numpy==1.21.6 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.0 -pandas==1.3.5 -pandas-stubs==1.2.0.62 -pillow==9.5.0 -pluggy==1.2.0 -pydantic==2.5.3 -pydantic-core==2.14.6 -pytest==7.4.4 -pytest-asyncio==0.21.1 -pytest-cov==4.1.0 -pytest-mock==3.11.1 -pytest-randomly==3.12.0 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyyaml==6.0.1 -six==1.16.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.0.1 -tqdm==4.66.5 -typing-extensions==4.7.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.15.0 diff --git a/riotfile.py b/riotfile.py index d139a9bfcc2..d97ac90042d 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2504,18 +2504,19 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT }, ), Venv( - pys=select_pys(min_version="3.7"), + pys=select_pys(min_version="3.8", max_version="3.12"), pkgs={ "openai[embeddings,datalib]": ["==1.1.1", "==1.30.1"], "pillow": "==9.5.0", + "httpx": "==0.27.2", }, ), Venv( pys=select_pys(min_version="3.8"), pkgs={ - "openai[datalib]": ["==1.30.1"], + "openai": latest, "tiktoken": latest, - "pillow": "==10.1.0", + "pillow": latest, }, env={"TIKTOKEN_AVAILABLE": "True"}, ), From db99f608169c701ac7d8586e3f5fe7a98cff592f Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Wed, 22 Jan 2025 13:00:09 -0500 Subject: [PATCH 03/11] Fix patching --- ddtrace/contrib/internal/openai/patch.py | 4 ++-- tests/contrib/openai/test_openai_patch.py | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ddtrace/contrib/internal/openai/patch.py b/ddtrace/contrib/internal/openai/patch.py index 77f7689a70e..7698808e947 100644 --- a/ddtrace/contrib/internal/openai/patch.py +++ b/ddtrace/contrib/internal/openai/patch.py @@ -195,7 +195,7 @@ def unpatch(): import openai.api_requestor unwrap(openai.api_requestor, "_make_session") - wrap(openai.util, "convert_to_openai_object") + unwrap(openai.util, "convert_to_openai_object") for resource, method_hook_dict in _RESOURCES.items(): if deep_getattr(openai.api_resources, resource) is None: @@ -224,7 +224,7 @@ def patched_client_init(openai, pin, func, instance, args, kwargs): return -def _patched_make_session(func, args, kwargs): +def _patched_make_session(func, instance, args, kwargs): """Patch for `openai.api_requestor._make_session` which sets the service name on the requests session so that spans from the requests integration will use the service name openai. This is done so that the service break down will include OpenAI time spent querying the OpenAI backend. diff --git a/tests/contrib/openai/test_openai_patch.py b/tests/contrib/openai/test_openai_patch.py index 50a566626dd..038de9ff5ab 100644 --- a/tests/contrib/openai/test_openai_patch.py +++ b/tests/contrib/openai/test_openai_patch.py @@ -100,11 +100,12 @@ def assert_module_patched(self, openai): self.assert_wrapped(openai.api_resources.file.File.retrieve) self.assert_wrapped(openai.api_resources.file.File.list) self.assert_wrapped(openai.api_resources.file.File.delete) - self.assert_wrapped(openai.api_resources.file.File.aretrieve_content) + self.assert_wrapped(openai.api_resources.file.File.download) self.assert_wrapped(openai.api_resources.file.File.acreate) self.assert_wrapped(openai.api_resources.file.File.aretrieve) self.assert_wrapped(openai.api_resources.file.File.alist) self.assert_wrapped(openai.api_resources.file.File.adelete) + self.assert_wrapped(openai.api_resources.file.File.adownload) def assert_not_module_patched(self, openai): if OPENAI_VERSION >= (1, 0, 0): @@ -189,11 +190,12 @@ def assert_not_module_patched(self, openai): self.assert_not_wrapped(openai.api_resources.file.File.retrieve) self.assert_not_wrapped(openai.api_resources.file.File.list) self.assert_not_wrapped(openai.api_resources.file.File.delete) - self.assert_not_wrapped(openai.api_resources.file.File.aretrieve_content) + self.assert_not_wrapped(openai.api_resources.file.File.download) self.assert_not_wrapped(openai.api_resources.file.File.acreate) self.assert_not_wrapped(openai.api_resources.file.File.aretrieve) self.assert_not_wrapped(openai.api_resources.file.File.alist) self.assert_not_wrapped(openai.api_resources.file.File.adelete) + self.assert_not_wrapped(openai.api_resources.file.File.adownload) def assert_not_module_double_patched(self, openai): if OPENAI_VERSION >= (1, 0, 0): @@ -278,8 +280,9 @@ def assert_not_module_double_patched(self, openai): self.assert_not_double_wrapped(openai.api_resources.file.File.retrieve) self.assert_not_double_wrapped(openai.api_resources.file.File.list) self.assert_not_double_wrapped(openai.api_resources.file.File.delete) - self.assert_not_double_wrapped(openai.api_resources.file.File.aretrieve_content) + self.assert_not_double_wrapped(openai.api_resources.file.File.download) self.assert_not_double_wrapped(openai.api_resources.file.File.acreate) self.assert_not_double_wrapped(openai.api_resources.file.File.aretrieve) self.assert_not_double_wrapped(openai.api_resources.file.File.alist) self.assert_not_double_wrapped(openai.api_resources.file.File.adelete) + self.assert_not_double_wrapped(openai.api_resources.file.File.adownload) From 037e5b5084dc2cd68875e2fecf136f177b362162 Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Wed, 22 Jan 2025 15:16:26 -0500 Subject: [PATCH 04/11] Fix v0 endpoint patching --- ddtrace/contrib/internal/openai/patch.py | 11 ++++++----- riotfile.py | 2 +- tests/contrib/openai/test_openai_patch.py | 3 --- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/ddtrace/contrib/internal/openai/patch.py b/ddtrace/contrib/internal/openai/patch.py index 7698808e947..83f28596c41 100644 --- a/ddtrace/contrib/internal/openai/patch.py +++ b/ddtrace/contrib/internal/openai/patch.py @@ -82,8 +82,9 @@ def get_version(): else: _RESOURCES = { "model.Model": { - "list": _endpoint_hooks._ListHook, - "retrieve": _endpoint_hooks._RetrieveHook, + "list": _endpoint_hooks._ModelListHook, + "retrieve": _endpoint_hooks._ModelRetrieveHook, + "delete": _endpoint_hooks._ModelDeleteHook, }, "completion.Completion": { "create": _endpoint_hooks._CompletionHook, @@ -107,10 +108,10 @@ def get_version(): "create": _endpoint_hooks._ModerationHook, }, "file.File": { - # File.list() and File.retrieve() share the same underlying method as Model.list() and Model.retrieve() - # which means they are already wrapped + "list": _endpoint_hooks._FileListHook, + "retrieve": _endpoint_hooks._FileRetrieveHook, "create": _endpoint_hooks._FileCreateHook, - "delete": _endpoint_hooks._DeleteHook, + "delete": _endpoint_hooks._FileDeleteHook, "download": _endpoint_hooks._FileDownloadHook, }, } diff --git a/riotfile.py b/riotfile.py index d97ac90042d..8330681b1ca 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2504,7 +2504,7 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT }, ), Venv( - pys=select_pys(min_version="3.8", max_version="3.12"), + pys=select_pys(min_version="3.8", max_version="3.11"), pkgs={ "openai[embeddings,datalib]": ["==1.1.1", "==1.30.1"], "pillow": "==9.5.0", diff --git a/tests/contrib/openai/test_openai_patch.py b/tests/contrib/openai/test_openai_patch.py index 038de9ff5ab..6a995213180 100644 --- a/tests/contrib/openai/test_openai_patch.py +++ b/tests/contrib/openai/test_openai_patch.py @@ -62,7 +62,6 @@ def assert_module_patched(self, openai): self.assert_wrapped(openai.resources.files.AsyncFiles.list) self.assert_wrapped(openai.resources.files.AsyncFiles.delete) self.assert_wrapped(openai.resources.files.AsyncFiles.retrieve_content) - else: self.assert_wrapped(openai.api_resources.completion.Completion.create) self.assert_wrapped(openai.api_resources.completion.Completion.acreate) @@ -152,7 +151,6 @@ def assert_not_module_patched(self, openai): self.assert_not_wrapped(openai.resources.files.AsyncFiles.list) self.assert_not_wrapped(openai.resources.files.AsyncFiles.delete) self.assert_not_wrapped(openai.resources.files.AsyncFiles.retrieve_content) - else: self.assert_not_wrapped(openai.api_resources.completion.Completion.create) self.assert_not_wrapped(openai.api_resources.completion.Completion.acreate) @@ -242,7 +240,6 @@ def assert_not_module_double_patched(self, openai): self.assert_not_double_wrapped(openai.resources.files.AsyncFiles.list) self.assert_not_double_wrapped(openai.resources.files.AsyncFiles.delete) self.assert_not_double_wrapped(openai.resources.files.AsyncFiles.retrieve_content) - else: self.assert_not_double_wrapped(openai.api_resources.completion.Completion.create) self.assert_not_double_wrapped(openai.api_resources.completion.Completion.acreate) From 4a53ac6c437c5e18c79e3340bd97a8ca23bd3b56 Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Wed, 22 Jan 2025 16:43:46 -0500 Subject: [PATCH 05/11] Fix arg ordering after switch from bytecode wrapping (bytecode wrapping made args[0] be object self/cls ref) --- .../internal/openai/_endpoint_hooks.py | 100 +++++++++--------- ddtrace/contrib/internal/openai/patch.py | 8 +- ddtrace/contrib/openai/__init__.py | 1 - .../v1/completion_stream_wrong_api_key.yaml | 77 ++++++++++++++ tests/contrib/openai/test_openai_v1.py | 21 ++-- 5 files changed, 141 insertions(+), 66 deletions(-) create mode 100644 tests/contrib/openai/cassettes/v1/completion_stream_wrong_api_key.yaml diff --git a/ddtrace/contrib/internal/openai/_endpoint_hooks.py b/ddtrace/contrib/internal/openai/_endpoint_hooks.py index 979e1774a8a..193498b58aa 100644 --- a/ddtrace/contrib/internal/openai/_endpoint_hooks.py +++ b/ddtrace/contrib/internal/openai/_endpoint_hooks.py @@ -37,7 +37,7 @@ class _EndpointHook: OPERATION_ID = "" # Each endpoint hook must provide an operationID as specified in the OpenAI API specs: # https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml - def _record_request(self, pin, integration, span, args, kwargs): + def _record_request(self, pin, integration, instance, span, args, kwargs): """ Set base-level openai tags, as well as request params from args and kwargs. All inherited EndpointHook classes should include a super call to this method before performing @@ -45,12 +45,12 @@ def _record_request(self, pin, integration, span, args, kwargs): """ endpoint = self.ENDPOINT_NAME if endpoint is None: - endpoint = "%s" % args[0].OBJECT_NAME + endpoint = "%s" % getattr(instance, "OBJECT_NAME", "") span.set_tag_str("openai.request.endpoint", "/%s/%s" % (API_VERSION, endpoint)) span.set_tag_str("openai.request.method", self.HTTP_METHOD_TYPE) if self._request_arg_params and len(self._request_arg_params) > 1: - for idx, arg in enumerate(self._request_arg_params, 1): + for idx, arg in enumerate(self._request_arg_params): if idx >= len(args): break if arg is None or args[idx] is None: @@ -74,8 +74,8 @@ def _record_request(self, pin, integration, span, args, kwargs): else: span.set_tag_str("openai.request.%s" % kw_attr, str(kwargs[kw_attr])) - def handle_request(self, pin, integration, span, args, kwargs): - self._record_request(pin, integration, span, args, kwargs) + def handle_request(self, pin, integration, instance, span, args, kwargs): + self._record_request(pin, integration, instance, span, args, kwargs) resp, error = yield if hasattr(resp, "parse"): # Users can request the raw response, in which case we need to process on the parsed response @@ -186,8 +186,8 @@ class _CompletionHook(_BaseCompletionHook): HTTP_METHOD_TYPE = "POST" OPERATION_ID = "createCompletion" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) if integration.is_pc_sampled_span(span): prompt = kwargs.get("prompt", "") if isinstance(prompt, str): @@ -241,8 +241,8 @@ class _ChatCompletionHook(_BaseCompletionHook): HTTP_METHOD_TYPE = "POST" OPERATION_ID = "createChatCompletion" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) for idx, m in enumerate(kwargs.get("messages", [])): role = getattr(m, "role", "") name = getattr(m, "name", "") @@ -305,12 +305,12 @@ class _EmbeddingHook(_EndpointHook): HTTP_METHOD_TYPE = "POST" OPERATION_ID = "createEmbedding" - def _record_request(self, pin, integration, span, args, kwargs): + def _record_request(self, pin, integration, instance, span, args, kwargs): """ Embedding endpoint allows multiple inputs, each of which we specify a request tag for, so have to manually set them in _pre_response(). """ - super()._record_request(pin, integration, span, args, kwargs) + super()._record_request(pin, integration, instance, span, args, kwargs) embedding_input = kwargs.get("input", "") if integration.is_pc_sampled_span(span): if isinstance(embedding_input, str) or isinstance(embedding_input[0], int): @@ -340,8 +340,8 @@ class _ListHook(_EndpointHook): HTTP_METHOD_TYPE = "GET" OPERATION_ID = "list" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) endpoint = span.get_tag("openai.request.endpoint") if endpoint.endswith("/models"): span.resource = "listModels" @@ -399,15 +399,15 @@ class _RetrieveHook(_EndpointHook): HTTP_METHOD_TYPE = "GET" OPERATION_ID = "retrieve" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) endpoint = span.get_tag("openai.request.endpoint") if endpoint.endswith("/models"): span.resource = "retrieveModel" - span.set_tag_str("openai.request.model", args[1] if len(args) >= 2 else kwargs.get("model", "")) + span.set_tag_str("openai.request.model", args[0] if len(args) >= 1 else kwargs.get("model", "")) elif endpoint.endswith("/files"): span.resource = "retrieveFile" - span.set_tag_str("openai.request.file_id", args[1] if len(args) >= 2 else kwargs.get("file_id", "")) + span.set_tag_str("openai.request.file_id", args[1] if len(args) >= 1 else kwargs.get("file_id", "")) span.set_tag_str("openai.request.endpoint", "%s/*" % endpoint) def _record_response(self, pin, integration, span, args, kwargs, resp, error): @@ -434,9 +434,9 @@ class _ModelRetrieveHook(_RetrieveHook): ENDPOINT_NAME = "models" OPERATION_ID = "retrieveModel" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) - span.set_tag_str("openai.request.model", args[1] if len(args) >= 2 else kwargs.get("model", "")) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) + span.set_tag_str("openai.request.model", args[0] if len(args) >= 1 else kwargs.get("model", "")) class _FileRetrieveHook(_RetrieveHook): @@ -447,9 +447,9 @@ class _FileRetrieveHook(_RetrieveHook): ENDPOINT_NAME = "files" OPERATION_ID = "retrieveFile" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) - span.set_tag_str("openai.request.file_id", args[1] if len(args) >= 2 else kwargs.get("file_id", "")) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) + span.set_tag_str("openai.request.file_id", args[0] if len(args) >= 1 else kwargs.get("file_id", "")) class _DeleteHook(_EndpointHook): @@ -461,15 +461,15 @@ class _DeleteHook(_EndpointHook): HTTP_METHOD_TYPE = "DELETE" OPERATION_ID = "delete" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) endpoint = span.get_tag("openai.request.endpoint") if endpoint.endswith("/models"): span.resource = "deleteModel" - span.set_tag_str("openai.request.model", args[1] if len(args) >= 2 else kwargs.get("model", "")) + span.set_tag_str("openai.request.model", args[0] if len(args) >= 1 else kwargs.get("model", "")) elif endpoint.endswith("/files"): span.resource = "deleteFile" - span.set_tag_str("openai.request.file_id", args[1] if len(args) >= 2 else kwargs.get("file_id", "")) + span.set_tag_str("openai.request.file_id", args[0] if len(args) >= 1 else kwargs.get("file_id", "")) span.set_tag_str("openai.request.endpoint", "%s/*" % endpoint) def _record_response(self, pin, integration, span, args, kwargs, resp, error): @@ -508,8 +508,8 @@ class _ImageHook(_EndpointHook): ENDPOINT_NAME = "images" HTTP_METHOD_TYPE = "POST" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) span.set_tag_str("openai.request.model", "dall-e") def _record_response(self, pin, integration, span, args, kwargs, resp, error): @@ -526,10 +526,10 @@ def _record_response(self, pin, integration, span, args, kwargs, resp, error): if "prompt" in self._request_kwarg_params: attrs_dict.update({"prompt": kwargs.get("prompt", "")}) if "image" in self._request_kwarg_params: - image = args[1] if len(args) >= 2 else kwargs.get("image", "") + image = args[0] if len(args) >= 1 else kwargs.get("image", "") attrs_dict.update({"image": image.name.split("/")[-1]}) if "mask" in self._request_kwarg_params: - mask = args[2] if len(args) >= 3 else kwargs.get("mask", "") + mask = args[1] if len(args) >= 2 else kwargs.get("mask", "") attrs_dict.update({"mask": mask.name.split("/")[-1]}) integration.log( span, "info" if error is None else "error", "sampled %s" % self.OPERATION_ID, attrs=attrs_dict @@ -560,12 +560,12 @@ class _ImageEditHook(_ImageHook): ENDPOINT_NAME = "images/edits" OPERATION_ID = "createImageEdit" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) if not integration.is_pc_sampled_span: return - image = args[1] if len(args) >= 2 else kwargs.get("image", "") - mask = args[2] if len(args) >= 3 else kwargs.get("mask", "") + image = args[0] if len(args) >= 1 else kwargs.get("image", "") + mask = args[1] if len(args) >= 2 else kwargs.get("mask", "") if image: if hasattr(image, "name"): span.set_tag_str("openai.request.image", integration.trunc(image.name.split("/")[-1])) @@ -584,11 +584,11 @@ class _ImageVariationHook(_ImageHook): ENDPOINT_NAME = "images/variations" OPERATION_ID = "createImageVariation" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) if not integration.is_pc_sampled_span: return - image = args[1] if len(args) >= 2 else kwargs.get("image", "") + image = args[0] if len(args) >= 1 else kwargs.get("image", "") if image: if hasattr(image, "name"): span.set_tag_str("openai.request.image", integration.trunc(image.name.split("/")[-1])) @@ -602,11 +602,11 @@ class _BaseAudioHook(_EndpointHook): ENDPOINT_NAME = "audio" HTTP_METHOD_TYPE = "POST" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) if not integration.is_pc_sampled_span: return - audio_file = args[2] if len(args) >= 3 else kwargs.get("file", "") + audio_file = args[1] if len(args) >= 2 else kwargs.get("file", "") if audio_file and hasattr(audio_file, "name"): span.set_tag_str("openai.request.filename", integration.trunc(audio_file.name.split("/")[-1])) else: @@ -626,7 +626,7 @@ def _record_response(self, pin, integration, span, args, kwargs, resp, error): if integration.is_pc_sampled_span(span): span.set_tag_str("openai.response.text", integration.trunc(text)) if integration.is_pc_sampled_log(span): - file_input = args[2] if len(args) >= 3 else kwargs.get("file", "") + file_input = args[1] if len(args) >= 2 else kwargs.get("file", "") integration.log( span, "info" if error is None else "error", @@ -685,8 +685,8 @@ class _ModerationHook(_EndpointHook): HTTP_METHOD_TYPE = "POST" OPERATION_ID = "createModeration" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) def _record_response(self, pin, integration, span, args, kwargs, resp, error): resp = super()._record_response(pin, integration, span, args, kwargs, resp, error) @@ -723,9 +723,9 @@ class _FileCreateHook(_BaseFileHook): HTTP_METHOD_TYPE = "POST" OPERATION_ID = "createFile" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) - fp = args[1] if len(args) >= 2 else kwargs.get("file", "") + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) + fp = args[0] if len(args) >= 1 else kwargs.get("file", "") if fp and hasattr(fp, "name"): span.set_tag_str("openai.request.filename", fp.name.split("/")[-1]) else: @@ -742,9 +742,9 @@ class _FileDownloadHook(_BaseFileHook): OPERATION_ID = "downloadFile" ENDPOINT_NAME = "files/*/content" - def _record_request(self, pin, integration, span, args, kwargs): - super()._record_request(pin, integration, span, args, kwargs) - span.set_tag_str("openai.request.file_id", args[1] if len(args) >= 2 else kwargs.get("file_id", "")) + def _record_request(self, pin, integration, instance, span, args, kwargs): + super()._record_request(pin, integration, instance, span, args, kwargs) + span.set_tag_str("openai.request.file_id", args[0] if len(args) >= 1 else kwargs.get("file_id", "")) def _record_response(self, pin, integration, span, args, kwargs, resp, error): resp = super()._record_response(pin, integration, span, args, kwargs, resp, error) diff --git a/ddtrace/contrib/internal/openai/patch.py b/ddtrace/contrib/internal/openai/patch.py index 83f28596c41..39f79d13795 100644 --- a/ddtrace/contrib/internal/openai/patch.py +++ b/ddtrace/contrib/internal/openai/patch.py @@ -238,7 +238,7 @@ def _patched_make_session(func, instance, args, kwargs): return session -def _traced_endpoint(endpoint_hook, integration, pin, args, kwargs): +def _traced_endpoint(endpoint_hook, integration, instance, pin, args, kwargs): span = integration.trace(pin, endpoint_hook.OPERATION_ID) openai_api_key = _format_openai_api_key(kwargs.get("api_key")) err = None @@ -247,7 +247,7 @@ def _traced_endpoint(endpoint_hook, integration, pin, args, kwargs): span.set_tag_str("openai.user.api_key", openai_api_key) try: # Start the hook - hook = endpoint_hook().handle_request(pin, integration, span, args, kwargs) + hook = endpoint_hook().handle_request(pin, integration, instance, span, args, kwargs) hook.send(None) resp, err = yield @@ -275,7 +275,7 @@ def _patched_endpoint(openai, patch_hook): @with_traced_module def patched_endpoint(openai, pin, func, instance, args, kwargs): integration = openai._datadog_integration - g = _traced_endpoint(patch_hook, integration, pin, args, kwargs) + g = _traced_endpoint(patch_hook, integration, instance, pin, args, kwargs) g.send(None) resp, err = None, None try: @@ -300,7 +300,7 @@ def _patched_endpoint_async(openai, patch_hook): @with_traced_module async def patched_endpoint(openai, pin, func, instance, args, kwargs): integration = openai._datadog_integration - g = _traced_endpoint(patch_hook, integration, pin, args, kwargs) + g = _traced_endpoint(patch_hook, integration, instance, pin, args, kwargs) g.send(None) resp, err = None, None try: diff --git a/ddtrace/contrib/openai/__init__.py b/ddtrace/contrib/openai/__init__.py index 88090b5f85a..da94047c2e8 100644 --- a/ddtrace/contrib/openai/__init__.py +++ b/ddtrace/contrib/openai/__init__.py @@ -248,7 +248,6 @@ Pin.override(openai, service="my-openai-service") """ # noqa: E501 - # Required to allow users to import from `ddtrace.contrib.openai.patch` directly import warnings as _w diff --git a/tests/contrib/openai/cassettes/v1/completion_stream_wrong_api_key.yaml b/tests/contrib/openai/cassettes/v1/completion_stream_wrong_api_key.yaml new file mode 100644 index 00000000000..512263ce56c --- /dev/null +++ b/tests/contrib/openai/cassettes/v1/completion_stream_wrong_api_key.yaml @@ -0,0 +1,77 @@ +interactions: +- request: + body: '{"model":"text-curie-001","prompt":"how does openai tokenize prompts?","max_tokens":150,"n":1,"stream":true,"temperature":0.8}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '126' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.59.7 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.59.7 + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.13.1 + method: POST + uri: https://api.openai.com/v1/completions + response: + body: + string: "{\n \"error\": {\n \"message\": \"Incorrect API key provided: + sk-wrong****-key. You can find your API key at https://platform.openai.com/account/api-keys.\",\n + \ \"type\": \"invalid_request_error\",\n \"param\": null,\n \"code\": + \"invalid_api_key\"\n }\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 9058b3cc3bcdd63c-IAD + Connection: + - keep-alive + Content-Length: + - '266' + Content-Type: + - application/json; charset=utf-8 + Date: + - Tue, 21 Jan 2025 16:32:48 GMT + Server: + - cloudflare + Set-Cookie: + - __cf_bm=WUZdhCkUNTJUEkju8qgk4MKCHL7CFOaIUNvU0L9XmvA-1737477168-1.0.1.1-RJ7MOiDyJEfHrXSN0WQVgZFtkxlkwBL3p.5t3._uu77WPJSM8tYzI3wMHSu.yMwD9QkrbgR5yavkTN.RTWl_1A; + path=/; expires=Tue, 21-Jan-25 17:02:48 GMT; domain=.api.openai.com; HttpOnly; + Secure; SameSite=None + - _cfuvid=7KOfpy1ICNI532AjhDxBh2qtnyNpsjauHeWi6dEJgT4-1737477168271-0.0.1.1-604800000; + path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + X-Content-Type-Options: + - nosniff + alt-svc: + - h3=":443"; ma=86400 + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + vary: + - Origin + x-request-id: + - req_c45bfc7515dca54ef87c667f8210af23 + status: + code: 401 + message: Unauthorized +version: 1 diff --git a/tests/contrib/openai/test_openai_v1.py b/tests/contrib/openai/test_openai_v1.py index 6468c696d0f..e8962ad414f 100644 --- a/tests/contrib/openai/test_openai_v1.py +++ b/tests/contrib/openai/test_openai_v1.py @@ -856,17 +856,16 @@ def test_misuse(openai, snapshot_tracer): ) def test_span_finish_on_stream_error(openai, openai_vcr, snapshot_tracer): with openai_vcr.use_cassette("completion_stream_wrong_api_key.yaml"): - with pytest.raises(openai.APIConnectionError): - with pytest.raises(openai.AuthenticationError): - client = openai.OpenAI(api_key="sk-wrong-api-key") - client.completions.create( - model="text-curie-001", - prompt="how does openai tokenize prompts?", - temperature=0.8, - n=1, - max_tokens=150, - stream=True, - ) + with pytest.raises((openai.APIConnectionError, openai.AuthenticationError)): + client = openai.OpenAI(api_key="sk-wrong-api-key") + client.completions.create( + model="text-curie-001", + prompt="how does openai tokenize prompts?", + temperature=0.8, + n=1, + max_tokens=150, + stream=True, + ) @pytest.mark.snapshot From 3232d6af90e067056ec02b763cf5422cb84a086f Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Thu, 23 Jan 2025 14:14:18 -0500 Subject: [PATCH 06/11] Skip azure tests for latest openai, make file delete compatible with v0 --- .../contrib/internal/openai/_endpoint_hooks.py | 5 ++++- tests/contrib/openai/test_openai_llmobs.py | 16 ++++++++++++++++ tests/contrib/openai/test_openai_v1.py | 18 ++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/ddtrace/contrib/internal/openai/_endpoint_hooks.py b/ddtrace/contrib/internal/openai/_endpoint_hooks.py index 193498b58aa..147192460b8 100644 --- a/ddtrace/contrib/internal/openai/_endpoint_hooks.py +++ b/ddtrace/contrib/internal/openai/_endpoint_hooks.py @@ -469,7 +469,10 @@ def _record_request(self, pin, integration, instance, span, args, kwargs): span.set_tag_str("openai.request.model", args[0] if len(args) >= 1 else kwargs.get("model", "")) elif endpoint.endswith("/files"): span.resource = "deleteFile" - span.set_tag_str("openai.request.file_id", args[0] if len(args) >= 1 else kwargs.get("file_id", "")) + if len(args) >= 1: + span.set_tag_str("openai.request.file_id", args[0]) + else: + span.set_tag_str("openai.request.file_id", kwargs.get("file_id", kwargs.get("sid", ""))) span.set_tag_str("openai.request.endpoint", "%s/*" % endpoint) def _record_response(self, pin, integration, span, args, kwargs, resp, error): diff --git a/tests/contrib/openai/test_openai_llmobs.py b/tests/contrib/openai/test_openai_llmobs.py index a145877c8c8..b3e17011300 100644 --- a/tests/contrib/openai/test_openai_llmobs.py +++ b/tests/contrib/openai/test_openai_llmobs.py @@ -339,6 +339,10 @@ def test_completion(self, openai, ddtrace_global_config, mock_llmobs_writer, moc ) ) + @pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), + reason="latest openai versions use modified azure requests" + ) def test_completion_azure( self, openai, azure_openai_config, ddtrace_global_config, mock_llmobs_writer, mock_tracer ): @@ -369,6 +373,10 @@ def test_completion_azure( ) ) + @pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), + reason="latest openai versions use modified azure requests" + ) async def test_completion_azure_async( self, openai, azure_openai_config, ddtrace_global_config, mock_llmobs_writer, mock_tracer ): @@ -458,6 +466,10 @@ def test_chat_completion(self, openai, ddtrace_global_config, mock_llmobs_writer ) ) + @pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), + reason="latest openai versions use modified azure requests" + ) def test_chat_completion_azure( self, openai, azure_openai_config, ddtrace_global_config, mock_llmobs_writer, mock_tracer ): @@ -488,6 +500,10 @@ def test_chat_completion_azure( ) ) + @pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), + reason="latest openai versions use modified azure requests" + ) async def test_chat_completion_azure_async( self, openai, azure_openai_config, ddtrace_global_config, mock_llmobs_writer, mock_tracer ): diff --git a/tests/contrib/openai/test_openai_v1.py b/tests/contrib/openai/test_openai_v1.py index e8962ad414f..438b980d5b5 100644 --- a/tests/contrib/openai/test_openai_v1.py +++ b/tests/contrib/openai/test_openai_v1.py @@ -1330,6 +1330,9 @@ def test_est_tokens(): ) # oracle: 92 +@pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), reason="latest openai versions use modified azure requests" +) @pytest.mark.snapshot( token="tests.contrib.openai.test_openai.test_azure_openai_completion", ignores=["meta.http.useragent", "meta.openai.api_base", "meta.openai.api_type", "meta.openai.api_version"], @@ -1352,6 +1355,9 @@ def test_azure_openai_completion(openai, azure_openai_config, openai_vcr, snapsh ) +@pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), reason="latest openai versions use modified azure requests" +) @pytest.mark.snapshot( token="tests.contrib.openai.test_openai.test_azure_openai_completion", ignores=[ @@ -1381,6 +1387,9 @@ async def test_azure_openai_acompletion(openai, azure_openai_config, openai_vcr, ) +@pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), reason="latest openai versions use modified azure requests" +) @pytest.mark.snapshot( token="tests.contrib.openai.test_openai.test_azure_openai_chat_completion", ignores=["meta.http.useragent", "meta.openai.api_base", "meta.openai.api_type", "meta.openai.api_version"], @@ -1403,6 +1412,9 @@ def test_azure_openai_chat_completion(openai, azure_openai_config, openai_vcr, s ) +@pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), reason="latest openai versions use modified azure requests" +) @pytest.mark.snapshot( token="tests.contrib.openai.test_openai.test_azure_openai_chat_completion", ignores=["meta.http.useragent", "meta.openai.api_base", "meta.openai.api_type", "meta.openai.api_version"], @@ -1425,6 +1437,9 @@ async def test_azure_openai_chat_acompletion(openai, azure_openai_config, openai ) +@pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), reason="latest openai versions use modified azure requests" +) @pytest.mark.snapshot( token="tests.contrib.openai.test_openai.test_azure_openai_embedding", ignores=["meta.http.useragent", "meta.openai.api_base", "meta.openai.api_type", "meta.openai.api_version"], @@ -1444,6 +1459,9 @@ def test_azure_openai_embedding(openai, azure_openai_config, openai_vcr, snapsho ) +@pytest.mark.skipif( + parse_version(openai_module.version.VERSION) >= (1, 60), reason="latest openai versions use modified azure requests" +) @pytest.mark.snapshot( token="tests.contrib.openai.test_openai.test_azure_openai_embedding", ignores=["meta.http.useragent", "meta.openai.api_base", "meta.openai.api_type", "meta.openai.api_version"], From 596a240ab399666f036c9bda391ca2a1cb2d6255 Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Thu, 23 Jan 2025 14:26:40 -0500 Subject: [PATCH 07/11] Remove tests for 3.7 --- .riot/requirements/129c849.txt | 50 ---------------------- .riot/requirements/1825740.txt | 49 --------------------- .riot/requirements/1bfbfdd.txt | 50 ---------------------- riotfile.py | 11 ----- tests/contrib/openai/test_openai_llmobs.py | 8 ++-- 5 files changed, 4 insertions(+), 164 deletions(-) delete mode 100644 .riot/requirements/129c849.txt delete mode 100644 .riot/requirements/1825740.txt delete mode 100644 .riot/requirements/1bfbfdd.txt diff --git a/.riot/requirements/129c849.txt b/.riot/requirements/129c849.txt deleted file mode 100644 index 1a2dded5bb8..00000000000 --- a/.riot/requirements/129c849.txt +++ /dev/null @@ -1,50 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --no-annotate .riot/requirements/129c849.in -# -annotated-types==0.7.0 -anyio==4.8.0 -attrs==24.3.0 -certifi==2024.12.14 -coverage[toml]==7.6.10 -distro==1.9.0 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.27.2 -hypothesis==6.45.0 -idna==3.10 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.1.0 -numpy==2.2.2 -openai[datalib,embeddings]==1.30.1 -opentracing==2.4.0 -packaging==24.2 -pandas==2.2.3 -pandas-stubs==2.2.3.241126 -pillow==9.5.0 -pluggy==1.5.0 -propcache==0.2.1 -pydantic==2.10.5 -pydantic-core==2.27.2 -pytest==8.3.4 -pytest-asyncio==0.21.1 -pytest-cov==6.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.16.0 -python-dateutil==2.9.0.post0 -pytz==2024.2 -pyyaml==6.0.2 -six==1.17.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tqdm==4.67.1 -types-pytz==2024.2.0.20241221 -typing-extensions==4.12.2 -tzdata==2025.1 -urllib3==1.26.20 -vcrpy==4.2.1 -wrapt==1.17.2 -yarl==1.18.3 diff --git a/.riot/requirements/1825740.txt b/.riot/requirements/1825740.txt deleted file mode 100644 index b4660fad985..00000000000 --- a/.riot/requirements/1825740.txt +++ /dev/null @@ -1,49 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.7 -# by the following command: -# -# pip-compile --allow-unsafe --config=pyproject.toml --no-annotate --resolver=backtracking .riot/requirements/1825740.in -# -aiohttp==3.8.6 -aiosignal==1.3.1 -async-timeout==4.0.3 -asynctest==0.13.0 -attrs==24.2.0 -certifi==2024.7.4 -charset-normalizer==3.3.2 -coverage[toml]==7.2.7 -exceptiongroup==1.2.2 -frozenlist==1.3.3 -hypothesis==6.45.0 -idna==3.8 -importlib-metadata==6.7.0 -iniconfig==2.0.0 -joblib==1.3.2 -mock==5.1.0 -multidict==6.0.5 -numpy==1.21.6 -openai==0.26.5 -opentracing==2.4.0 -packaging==24.0 -pillow==9.5.0 -pluggy==1.2.0 -pytest==7.4.4 -pytest-asyncio==0.21.1 -pytest-cov==4.1.0 -pytest-mock==3.11.1 -pytest-randomly==3.12.0 -pyyaml==6.0.1 -requests==2.31.0 -scikit-learn==1.0.2 -scipy==1.7.3 -six==1.16.0 -sortedcontainers==2.4.0 -threadpoolctl==3.1.0 -tomli==2.0.1 -tqdm==4.66.5 -typing-extensions==4.7.1 -urllib3==1.26.19 -vcrpy==4.2.1 -wrapt==1.16.0 -yarl==1.9.4 -zipp==3.15.0 diff --git a/.riot/requirements/1bfbfdd.txt b/.riot/requirements/1bfbfdd.txt deleted file mode 100644 index 42907f03519..00000000000 --- a/.riot/requirements/1bfbfdd.txt +++ /dev/null @@ -1,50 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --no-annotate .riot/requirements/1bfbfdd.in -# -annotated-types==0.7.0 -anyio==3.7.1 -attrs==24.3.0 -certifi==2024.12.14 -coverage[toml]==7.6.10 -distro==1.9.0 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.27.2 -hypothesis==6.45.0 -idna==3.10 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.1.0 -numpy==2.2.2 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.2 -pandas==2.2.3 -pandas-stubs==2.2.3.241126 -pillow==9.5.0 -pluggy==1.5.0 -propcache==0.2.1 -pydantic==2.10.5 -pydantic-core==2.27.2 -pytest==8.3.4 -pytest-asyncio==0.21.1 -pytest-cov==6.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.16.0 -python-dateutil==2.9.0.post0 -pytz==2024.2 -pyyaml==6.0.2 -six==1.17.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tqdm==4.67.1 -types-pytz==2024.2.0.20241221 -typing-extensions==4.12.2 -tzdata==2025.1 -urllib3==1.26.20 -vcrpy==4.2.1 -wrapt==1.17.2 -yarl==1.18.3 diff --git a/riotfile.py b/riotfile.py index 8330681b1ca..df553590306 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2492,17 +2492,6 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT "pytest-randomly": latest, }, venvs=[ - Venv( - # openai[embeddings] broken install with sklearn was never fixed on 0.26 - # https://github.com/openai/openai-python/issues/210 - pys="3.7", - env={"SKLEARN_ALLOW_DEPRECATED_SKLEARN_PACKAGE_INSTALL": "True"}, - pkgs={ - "openai": "==0.26.5", - "scikit-learn": "==1.0.2", - "pillow": "==9.5.0", - }, - ), Venv( pys=select_pys(min_version="3.8", max_version="3.11"), pkgs={ diff --git a/tests/contrib/openai/test_openai_llmobs.py b/tests/contrib/openai/test_openai_llmobs.py index b3e17011300..4c15b1ffad3 100644 --- a/tests/contrib/openai/test_openai_llmobs.py +++ b/tests/contrib/openai/test_openai_llmobs.py @@ -341,7 +341,7 @@ def test_completion(self, openai, ddtrace_global_config, mock_llmobs_writer, moc @pytest.mark.skipif( parse_version(openai_module.version.VERSION) >= (1, 60), - reason="latest openai versions use modified azure requests" + reason="latest openai versions use modified azure requests", ) def test_completion_azure( self, openai, azure_openai_config, ddtrace_global_config, mock_llmobs_writer, mock_tracer @@ -375,7 +375,7 @@ def test_completion_azure( @pytest.mark.skipif( parse_version(openai_module.version.VERSION) >= (1, 60), - reason="latest openai versions use modified azure requests" + reason="latest openai versions use modified azure requests", ) async def test_completion_azure_async( self, openai, azure_openai_config, ddtrace_global_config, mock_llmobs_writer, mock_tracer @@ -468,7 +468,7 @@ def test_chat_completion(self, openai, ddtrace_global_config, mock_llmobs_writer @pytest.mark.skipif( parse_version(openai_module.version.VERSION) >= (1, 60), - reason="latest openai versions use modified azure requests" + reason="latest openai versions use modified azure requests", ) def test_chat_completion_azure( self, openai, azure_openai_config, ddtrace_global_config, mock_llmobs_writer, mock_tracer @@ -502,7 +502,7 @@ def test_chat_completion_azure( @pytest.mark.skipif( parse_version(openai_module.version.VERSION) >= (1, 60), - reason="latest openai versions use modified azure requests" + reason="latest openai versions use modified azure requests", ) async def test_chat_completion_azure_async( self, openai, azure_openai_config, ddtrace_global_config, mock_llmobs_writer, mock_tracer From 0e202e997998def41d3518384016253337d0c71e Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Thu, 23 Jan 2025 15:41:28 -0500 Subject: [PATCH 08/11] Release note --- releasenotes/notes/fix-openai-313-29ec43cbf2f35947.yaml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 releasenotes/notes/fix-openai-313-29ec43cbf2f35947.yaml diff --git a/releasenotes/notes/fix-openai-313-29ec43cbf2f35947.yaml b/releasenotes/notes/fix-openai-313-29ec43cbf2f35947.yaml new file mode 100644 index 00000000000..59d818de9a9 --- /dev/null +++ b/releasenotes/notes/fix-openai-313-29ec43cbf2f35947.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + openai: Introduces tracing support to the OpenAI integration for Python versions 3.12 and 3.13. +fixes: + - | + openai: Fixes a patching issue where asynchronous moderation endpoint calls resulted in coroutine scheduling errors. From b42eafb21852bde549d92470092abe2ea0cc47a4 Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Thu, 23 Jan 2025 18:00:14 -0500 Subject: [PATCH 09/11] Keep 3.7 tests, remove openai v1.1 tests --- .../internal/openai/_endpoint_hooks.py | 25 ++++++++++--------- riotfile.py | 15 +++++++++-- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/ddtrace/contrib/internal/openai/_endpoint_hooks.py b/ddtrace/contrib/internal/openai/_endpoint_hooks.py index 147192460b8..00ee44aef4b 100644 --- a/ddtrace/contrib/internal/openai/_endpoint_hooks.py +++ b/ddtrace/contrib/internal/openai/_endpoint_hooks.py @@ -404,10 +404,16 @@ def _record_request(self, pin, integration, instance, span, args, kwargs): endpoint = span.get_tag("openai.request.endpoint") if endpoint.endswith("/models"): span.resource = "retrieveModel" - span.set_tag_str("openai.request.model", args[0] if len(args) >= 1 else kwargs.get("model", "")) + if len(args) >= 1: + span.set_tag_str("openai.request.model", args[0]) + else: + span.set_tag_str("openai.request.model", kwargs.get("model", kwargs.get("id", ""))) elif endpoint.endswith("/files"): span.resource = "retrieveFile" - span.set_tag_str("openai.request.file_id", args[1] if len(args) >= 1 else kwargs.get("file_id", "")) + if len(args) >= 1: + span.set_tag_str("openai.request.file_id", args[0]) + else: + span.set_tag_str("openai.request.file_id", kwargs.get("file_id", kwargs.get("id", ""))) span.set_tag_str("openai.request.endpoint", "%s/*" % endpoint) def _record_response(self, pin, integration, span, args, kwargs, resp, error): @@ -434,10 +440,6 @@ class _ModelRetrieveHook(_RetrieveHook): ENDPOINT_NAME = "models" OPERATION_ID = "retrieveModel" - def _record_request(self, pin, integration, instance, span, args, kwargs): - super()._record_request(pin, integration, instance, span, args, kwargs) - span.set_tag_str("openai.request.model", args[0] if len(args) >= 1 else kwargs.get("model", "")) - class _FileRetrieveHook(_RetrieveHook): """ @@ -447,10 +449,6 @@ class _FileRetrieveHook(_RetrieveHook): ENDPOINT_NAME = "files" OPERATION_ID = "retrieveFile" - def _record_request(self, pin, integration, instance, span, args, kwargs): - super()._record_request(pin, integration, instance, span, args, kwargs) - span.set_tag_str("openai.request.file_id", args[0] if len(args) >= 1 else kwargs.get("file_id", "")) - class _DeleteHook(_EndpointHook): """Hook for openai.DeletableAPIResource, which is used by File.delete, and Model.delete.""" @@ -466,7 +464,10 @@ def _record_request(self, pin, integration, instance, span, args, kwargs): endpoint = span.get_tag("openai.request.endpoint") if endpoint.endswith("/models"): span.resource = "deleteModel" - span.set_tag_str("openai.request.model", args[0] if len(args) >= 1 else kwargs.get("model", "")) + if len(args) >= 1: + span.set_tag_str("openai.request.model", args[0]) + else: + span.set_tag_str("openai.request.model", kwargs.get("model", kwargs.get("sid", ""))) elif endpoint.endswith("/files"): span.resource = "deleteFile" if len(args) >= 1: @@ -721,7 +722,7 @@ class _FileCreateHook(_BaseFileHook): "organization", "user_provided_filename", ) - _request_kwarg_params = ("purpose",) + _request_kwarg_params = ("purpose", "user_provided_filename") _response_attrs = ("id", "bytes", "created_at", "filename", "purpose", "status", "status_details") HTTP_METHOD_TYPE = "POST" OPERATION_ID = "createFile" diff --git a/riotfile.py b/riotfile.py index df553590306..2ca173ebe48 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2493,9 +2493,20 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT }, venvs=[ Venv( - pys=select_pys(min_version="3.8", max_version="3.11"), + # openai[embeddings] broken install with sklearn was never fixed on 0.26 + # https://github.com/openai/openai-python/issues/210 + pys="3.7", + env={"SKLEARN_ALLOW_DEPRECATED_SKLEARN_PACKAGE_INSTALL": "True"}, + pkgs={ + "openai": "==0.26.5", + "scikit-learn": "==1.0.2", + "pillow": "==9.5.0", + }, + ), + Venv( + pys=select_pys(min_version="3.7", max_version="3.11"), pkgs={ - "openai[embeddings,datalib]": ["==1.1.1", "==1.30.1"], + "openai[embeddings,datalib]": "==1.30.1", "pillow": "==9.5.0", "httpx": "==0.27.2", }, From 5081873ccbe42fe972f0f1053498bdf115fd685f Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Thu, 23 Jan 2025 18:13:49 -0500 Subject: [PATCH 10/11] Fix incompatible 3.7 riot venvs --- .riot/requirements/179818d.txt | 52 -------------------------------- .riot/requirements/18213af.txt | 47 +++++++++++++++++++++++++++++ .riot/requirements/1825740.txt | 49 ++++++++++++++++++++++++++++++ .riot/requirements/18d588e.txt | 50 ------------------------------- .riot/requirements/3db7151.txt | 54 ---------------------------------- .riot/requirements/900aca5.txt | 54 ---------------------------------- riotfile.py | 9 +++++- 7 files changed, 104 insertions(+), 211 deletions(-) delete mode 100644 .riot/requirements/179818d.txt create mode 100644 .riot/requirements/18213af.txt create mode 100644 .riot/requirements/1825740.txt delete mode 100644 .riot/requirements/18d588e.txt delete mode 100644 .riot/requirements/3db7151.txt delete mode 100644 .riot/requirements/900aca5.txt diff --git a/.riot/requirements/179818d.txt b/.riot/requirements/179818d.txt deleted file mode 100644 index bc6cd83028d..00000000000 --- a/.riot/requirements/179818d.txt +++ /dev/null @@ -1,52 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --no-annotate .riot/requirements/179818d.in -# -annotated-types==0.7.0 -anyio==3.7.1 -attrs==24.3.0 -certifi==2024.12.14 -coverage[toml]==7.6.10 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.27.2 -hypothesis==6.45.0 -idna==3.10 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.1.0 -numpy==2.2.2 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.2 -pandas==2.2.3 -pandas-stubs==2.2.3.241126 -pillow==9.5.0 -pluggy==1.5.0 -propcache==0.2.1 -pydantic==2.10.5 -pydantic-core==2.27.2 -pytest==8.3.4 -pytest-asyncio==0.21.1 -pytest-cov==6.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.16.0 -python-dateutil==2.9.0.post0 -pytz==2024.2 -pyyaml==6.0.2 -six==1.17.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.2.1 -tqdm==4.67.1 -types-pytz==2024.2.0.20241221 -typing-extensions==4.12.2 -tzdata==2025.1 -urllib3==1.26.20 -vcrpy==4.2.1 -wrapt==1.17.2 -yarl==1.18.3 diff --git a/.riot/requirements/18213af.txt b/.riot/requirements/18213af.txt new file mode 100644 index 00000000000..14ffa58351f --- /dev/null +++ b/.riot/requirements/18213af.txt @@ -0,0 +1,47 @@ +# +# This file is autogenerated by pip-compile with Python 3.7 +# by the following command: +# +# pip-compile --allow-unsafe --config=pyproject.toml --no-annotate --resolver=backtracking .riot/requirements/18213af.in +# +annotated-types==0.5.0 +anyio==3.7.1 +attrs==24.2.0 +cached-property==1.5.2 +certifi==2024.12.14 +coverage[toml]==7.2.7 +distro==1.9.0 +exceptiongroup==1.2.2 +h11==0.14.0 +httpcore==0.17.3 +httpx==0.24.1 +hypothesis==6.45.0 +idna==3.10 +importlib-metadata==6.7.0 +iniconfig==2.0.0 +mock==5.1.0 +multidict==6.0.5 +openai==1.30.1 +opentracing==2.4.0 +packaging==24.0 +pillow==9.5.0 +pluggy==1.2.0 +pydantic==2.5.3 +pydantic-core==2.14.6 +pytest==7.4.4 +pytest-asyncio==0.21.1 +pytest-cov==4.1.0 +pytest-mock==3.11.1 +pytest-randomly==3.12.0 +pyyaml==6.0.1 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tomli==2.0.1 +tqdm==4.67.1 +typing-extensions==4.7.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.16.0 +yarl==1.9.4 +zipp==3.15.0 diff --git a/.riot/requirements/1825740.txt b/.riot/requirements/1825740.txt new file mode 100644 index 00000000000..d1ef7a92bc0 --- /dev/null +++ b/.riot/requirements/1825740.txt @@ -0,0 +1,49 @@ +# +# This file is autogenerated by pip-compile with Python 3.7 +# by the following command: +# +# pip-compile --allow-unsafe --config=pyproject.toml --no-annotate --resolver=backtracking .riot/requirements/1825740.in +# +aiohttp==3.8.6 +aiosignal==1.3.1 +async-timeout==4.0.3 +asynctest==0.13.0 +attrs==24.2.0 +certifi==2024.12.14 +charset-normalizer==3.4.1 +coverage[toml]==7.2.7 +exceptiongroup==1.2.2 +frozenlist==1.3.3 +hypothesis==6.45.0 +idna==3.10 +importlib-metadata==6.7.0 +iniconfig==2.0.0 +joblib==1.3.2 +mock==5.1.0 +multidict==6.0.5 +numpy==1.21.6 +openai==0.26.5 +opentracing==2.4.0 +packaging==24.0 +pillow==9.5.0 +pluggy==1.2.0 +pytest==7.4.4 +pytest-asyncio==0.21.1 +pytest-cov==4.1.0 +pytest-mock==3.11.1 +pytest-randomly==3.12.0 +pyyaml==6.0.1 +requests==2.31.0 +scikit-learn==1.0.2 +scipy==1.7.3 +six==1.17.0 +sortedcontainers==2.4.0 +threadpoolctl==3.1.0 +tomli==2.0.1 +tqdm==4.67.1 +typing-extensions==4.7.1 +urllib3==1.26.20 +vcrpy==4.2.1 +wrapt==1.16.0 +yarl==1.9.4 +zipp==3.15.0 diff --git a/.riot/requirements/18d588e.txt b/.riot/requirements/18d588e.txt deleted file mode 100644 index 82bcdf7626f..00000000000 --- a/.riot/requirements/18d588e.txt +++ /dev/null @@ -1,50 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/18d588e.in -# -annotated-types==0.7.0 -anyio==3.7.1 -attrs==24.3.0 -certifi==2024.12.14 -coverage[toml]==7.6.10 -distro==1.9.0 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.27.2 -hypothesis==6.45.0 -idna==3.10 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.1.0 -numpy==2.2.2 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.2 -pandas==2.2.3 -pandas-stubs==2.2.3.241126 -pillow==9.5.0 -pluggy==1.5.0 -propcache==0.2.1 -pydantic==2.10.5 -pydantic-core==2.27.2 -pytest==8.3.4 -pytest-asyncio==0.21.1 -pytest-cov==6.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.16.0 -python-dateutil==2.9.0.post0 -pytz==2024.2 -pyyaml==6.0.2 -six==1.17.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tqdm==4.67.1 -types-pytz==2024.2.0.20241221 -typing-extensions==4.12.2 -tzdata==2025.1 -urllib3==1.26.20 -vcrpy==4.2.1 -wrapt==1.17.2 -yarl==1.18.3 diff --git a/.riot/requirements/3db7151.txt b/.riot/requirements/3db7151.txt deleted file mode 100644 index dcd3b85a214..00000000000 --- a/.riot/requirements/3db7151.txt +++ /dev/null @@ -1,54 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/3db7151.in -# -annotated-types==0.7.0 -anyio==3.7.1 -attrs==24.3.0 -certifi==2024.12.14 -coverage[toml]==7.6.10 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.27.2 -hypothesis==6.45.0 -idna==3.10 -importlib-metadata==8.6.1 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.1.0 -numpy==2.0.2 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.2 -pandas==2.2.3 -pandas-stubs==2.2.2.240807 -pillow==9.5.0 -pluggy==1.5.0 -propcache==0.2.1 -pydantic==2.10.5 -pydantic-core==2.27.2 -pytest==8.3.4 -pytest-asyncio==0.21.1 -pytest-cov==6.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.16.0 -python-dateutil==2.9.0.post0 -pytz==2024.2 -pyyaml==6.0.2 -six==1.17.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.2.1 -tqdm==4.67.1 -types-pytz==2024.2.0.20241221 -typing-extensions==4.12.2 -tzdata==2025.1 -urllib3==1.26.20 -vcrpy==4.2.1 -wrapt==1.17.2 -yarl==1.18.3 -zipp==3.21.0 diff --git a/.riot/requirements/900aca5.txt b/.riot/requirements/900aca5.txt deleted file mode 100644 index 5aed01fdb62..00000000000 --- a/.riot/requirements/900aca5.txt +++ /dev/null @@ -1,54 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.8 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/900aca5.in -# -annotated-types==0.7.0 -anyio==3.7.1 -attrs==24.3.0 -certifi==2024.12.14 -coverage[toml]==7.6.1 -distro==1.9.0 -exceptiongroup==1.2.2 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.27.2 -hypothesis==6.45.0 -idna==3.10 -importlib-metadata==8.5.0 -iniconfig==2.0.0 -mock==5.1.0 -multidict==6.1.0 -numpy==1.24.4 -openai[datalib,embeddings]==1.1.1 -opentracing==2.4.0 -packaging==24.2 -pandas==2.0.3 -pandas-stubs==2.0.3.230814 -pillow==9.5.0 -pluggy==1.5.0 -propcache==0.2.0 -pydantic==2.10.5 -pydantic-core==2.27.2 -pytest==8.3.4 -pytest-asyncio==0.21.1 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -python-dateutil==2.9.0.post0 -pytz==2024.2 -pyyaml==6.0.2 -six==1.17.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -tomli==2.2.1 -tqdm==4.67.1 -types-pytz==2024.2.0.20241221 -typing-extensions==4.12.2 -tzdata==2025.1 -urllib3==1.26.20 -vcrpy==4.2.1 -wrapt==1.17.2 -yarl==1.15.2 -zipp==3.20.2 diff --git a/riotfile.py b/riotfile.py index 2ca173ebe48..98912b1c38d 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2504,7 +2504,14 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT }, ), Venv( - pys=select_pys(min_version="3.7", max_version="3.11"), + pys="3.7", + pkgs={ + "openai": "==1.30.1", + "pillow": "==9.5.0", + }, + ), + Venv( + pys=select_pys(min_version="3.8", max_version="3.11"), pkgs={ "openai[embeddings,datalib]": "==1.30.1", "pillow": "==9.5.0", From a9c98cf917da40d019b4e4ae1d0072001236ea5f Mon Sep 17 00:00:00 2001 From: Yun Kim Date: Fri, 24 Jan 2025 10:47:21 -0500 Subject: [PATCH 11/11] Fix dependency for openai 1.30 tests --- .riot/requirements/{18213af.txt => df60af6.txt} | 9 +++++++-- riotfile.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) rename .riot/requirements/{18213af.txt => df60af6.txt} (82%) diff --git a/.riot/requirements/18213af.txt b/.riot/requirements/df60af6.txt similarity index 82% rename from .riot/requirements/18213af.txt rename to .riot/requirements/df60af6.txt index 14ffa58351f..5143f0e0a74 100644 --- a/.riot/requirements/18213af.txt +++ b/.riot/requirements/df60af6.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.7 # by the following command: # -# pip-compile --allow-unsafe --config=pyproject.toml --no-annotate --resolver=backtracking .riot/requirements/18213af.in +# pip-compile --allow-unsafe --config=pyproject.toml --no-annotate --resolver=backtracking .riot/requirements/df60af6.in # annotated-types==0.5.0 anyio==3.7.1 @@ -21,9 +21,12 @@ importlib-metadata==6.7.0 iniconfig==2.0.0 mock==5.1.0 multidict==6.0.5 -openai==1.30.1 +numpy==1.21.6 +openai[datalib]==1.30.1 opentracing==2.4.0 packaging==24.0 +pandas==1.3.5 +pandas-stubs==1.2.0.62 pillow==9.5.0 pluggy==1.2.0 pydantic==2.5.3 @@ -33,6 +36,8 @@ pytest-asyncio==0.21.1 pytest-cov==4.1.0 pytest-mock==3.11.1 pytest-randomly==3.12.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 pyyaml==6.0.1 six==1.17.0 sniffio==1.3.1 diff --git a/riotfile.py b/riotfile.py index 98912b1c38d..bcccd39c178 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2506,7 +2506,7 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT Venv( pys="3.7", pkgs={ - "openai": "==1.30.1", + "openai[datalib]": "==1.30.1", "pillow": "==9.5.0", }, ),