From f5a540c7ff32d77ebd39cf1a4e6c79cd7f718d64 Mon Sep 17 00:00:00 2001 From: etserend Date: Thu, 16 Jul 2026 17:36:40 -0500 Subject: [PATCH 1/3] =?UTF-8?q?chore(deps):=20bump=20ruff=20^0.12.3=20?= =?UTF-8?q?=E2=86=92=20^0.15.22=20and=20openapi-python-client=20^0.26.1=20?= =?UTF-8?q?=E2=86=92=20^0.29.0=20(HYBIM-777)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit openapi-python-client 0.26.x hard-caps ruff<0.14, so both versions must be bumped together. Also updates the ruff pre-commit hook rev to v0.15.22. Co-Authored-By: Claude Opus 4.7 --- .pre-commit-config.yaml | 2 +- poetry.lock | 95 +++++++++++++++++++++++------------------ pyproject.toml | 4 +- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 46c086e6..4981ec0c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: "v0.9.7" + rev: "v0.15.22" hooks: - id: ruff args: [--fix] diff --git a/poetry.lock b/poetry.lock index 4bd4bf43..c641a001 100644 --- a/poetry.lock +++ b/poetry.lock @@ -173,6 +173,19 @@ files = [ frozenlist = ">=1.1.0" typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} +[[package]] +name = "annotated-doc" +version = "0.0.4" +description = "Document parameters, class attributes, return types, and variables inline, with Annotated." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, + {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, +] +markers = {main = "(extra == \"crewai\" or extra == \"all\") and python_version <= \"3.13\""} + [[package]] name = "annotated-types" version = "0.7.0" @@ -614,14 +627,14 @@ dev = ["chroma-hnswlib (==0.7.6)", "fastapi (>=0.115.9)", "opentelemetry-instrum name = "click" version = "8.1.8" description = "Composable command line interface toolkit" -optional = false +optional = true python-versions = ">=3.7" -groups = ["main", "dev"] +groups = ["main"] +markers = "sys_platform != \"emscripten\" and (extra == \"openai\" or extra == \"all\") or python_version <= \"3.13\" and sys_platform != \"emscripten\" and (extra == \"openai\" or extra == \"all\" or extra == \"crewai\") or python_version <= \"3.13\" and (extra == \"crewai\" or extra == \"all\")" files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] -markers = {main = "sys_platform != \"emscripten\" and (extra == \"openai\" or extra == \"all\") or python_version <= \"3.13\" and sys_platform != \"emscripten\" and (extra == \"openai\" or extra == \"all\" or extra == \"crewai\") or python_version <= \"3.13\" and (extra == \"crewai\" or extra == \"all\")"} [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -2924,28 +2937,26 @@ voice = ["numpy (>=2.2.0,<3) ; python_version >= \"3.10\"", "websockets (>=15.0, [[package]] name = "openapi-python-client" -version = "0.26.1" +version = "0.29.0" description = "Generate modern Python clients from OpenAPI" optional = false -python-versions = "<4.0,>=3.9" +python-versions = "<4.0,>=3.11" groups = ["dev"] files = [ - {file = "openapi_python_client-0.26.1-py3-none-any.whl", hash = "sha256:415cb8095b1a3f15cec45670c5075c5097f65390a351d21512e8f6ea5c1be644"}, - {file = "openapi_python_client-0.26.1.tar.gz", hash = "sha256:e3832f0ef074a0ab591d1eeb5d3dab2ca820cd0349f7e79d9663b7b21206be5d"}, + {file = "openapi_python_client-0.29.0-py3-none-any.whl", hash = "sha256:1085864c1e0a42fb50e1f5eb84363b19de07ebfb8a3f82a146c8529b948b8f12"}, + {file = "openapi_python_client-0.29.0.tar.gz", hash = "sha256:4ff439a63765aaef548e69c4eedd86dfad57891dc322709450af0c2c9a72a23e"}, ] [package.dependencies] attrs = ">=22.2.0" colorama = {version = ">=0.4.3", markers = "sys_platform == \"win32\""} -httpx = ">=0.23.0,<0.29.0" +httpx = ">=0.23.1,<0.29.0" jinja2 = ">=3.0.0,<4.0.0" pydantic = ">=2.10,<3.0.0" -python-dateutil = ">=2.8.1,<3.0.0" -ruamel-yaml = ">=0.18.6,<0.19.0" -ruff = ">=0.2,<0.14" +ruamel-yaml = ">=0.18.6,<0.20.0" +ruff = ">=0.2" shellingham = ">=1.3.2,<2.0.0" -typer = ">0.6,<0.18" -typing-extensions = ">=4.8.0,<5.0.0" +typer = ">0.16,<0.27" [[package]] name = "openpyxl" @@ -4409,7 +4420,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev", "test"] +groups = ["main", "test"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -5029,30 +5040,30 @@ files = [ [[package]] name = "ruff" -version = "0.12.8" +version = "0.15.22" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.12.8-py3-none-linux_armv6l.whl", hash = "sha256:63cb5a5e933fc913e5823a0dfdc3c99add73f52d139d6cd5cc8639d0e0465513"}, - {file = "ruff-0.12.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a9bbe28f9f551accf84a24c366c1aa8774d6748438b47174f8e8565ab9dedbc"}, - {file = "ruff-0.12.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2fae54e752a3150f7ee0e09bce2e133caf10ce9d971510a9b925392dc98d2fec"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0acbcf01206df963d9331b5838fb31f3b44fa979ee7fa368b9b9057d89f4a53"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae3e7504666ad4c62f9ac8eedb52a93f9ebdeb34742b8b71cd3cccd24912719f"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb82efb5d35d07497813a1c5647867390a7d83304562607f3579602fa3d7d46f"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dbea798fc0065ad0b84a2947b0aff4233f0cb30f226f00a2c5850ca4393de609"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49ebcaccc2bdad86fd51b7864e3d808aad404aab8df33d469b6e65584656263a"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ac9c570634b98c71c88cb17badd90f13fc076a472ba6ef1d113d8ed3df109fb"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560e0cd641e45591a3e42cb50ef61ce07162b9c233786663fdce2d8557d99818"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:71c83121512e7743fba5a8848c261dcc454cafb3ef2934a43f1b7a4eb5a447ea"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:de4429ef2ba091ecddedd300f4c3f24bca875d3d8b23340728c3cb0da81072c3"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a2cab5f60d5b65b50fba39a8950c8746df1627d54ba1197f970763917184b161"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:45c32487e14f60b88aad6be9fd5da5093dbefb0e3e1224131cb1d441d7cb7d46"}, - {file = "ruff-0.12.8-py3-none-win32.whl", hash = "sha256:daf3475060a617fd5bc80638aeaf2f5937f10af3ec44464e280a9d2218e720d3"}, - {file = "ruff-0.12.8-py3-none-win_amd64.whl", hash = "sha256:7209531f1a1fcfbe8e46bcd7ab30e2f43604d8ba1c49029bb420b103d0b5f76e"}, - {file = "ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749"}, - {file = "ruff-0.12.8.tar.gz", hash = "sha256:4cb3a45525176e1009b2b64126acf5f9444ea59066262791febf55e40493a033"}, + {file = "ruff-0.15.22-py3-none-linux_armv6l.whl", hash = "sha256:44423e73493737f5e7c5b41d475483898ff37afcdae38bc3da5085e29af1c2d8"}, + {file = "ruff-0.15.22-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b82c6482946e9eda7ff2e091d25b8bad3f718684e1916d41bd56873cee05b697"}, + {file = "ruff-0.15.22-py3-none-macosx_11_0_arm64.whl", hash = "sha256:11c1c715af53a09f714e011106bffc419751ec8232fcb5da42173284ea3fec6f"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:742a29cf29bddb7c8327895d6a10e0e6c5b38a96dd407af9b5d0857f809c0576"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72af58b951b0ae395935ae79763dc349bc0eb706319d28f7a33ad2cfb3cfc178"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d425005c1835eb24e2ee4161cb90e8db263415f4a71c8c72c33abaa6c0c224"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b9b3f8779a4f08c969defc3c8c35abffaa757e601ed5ae66d6d1db6519969a"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e0dd1b2e4d3d585f897a0d137cbf4eaf6223bef4e8ce34d6bb12556c5f9249e"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365523eb91d9224e1bcb03b022fbf0facb8f9e23792a2c53d9d4b3924bdbdebb"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fabfd168afdf29fee5be98b831efa9683c94d7c5a3b58b9ce5a2e38444589a74"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:225dbf095a87f1d9f90f5fd7924d2613ee452a75a4308c63a8f50f761787aa7c"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1877d63b9d24ed278744f1523fd11b85540566d54641f97c566d7d9dc5ca5296"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1606c510bd7215680d32efab38965f7cdec3ef69f5170a3f4791404ffdd5262"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:630479b18625f5ffc373f77603a22a9f8ac0acd7ff0501178b5db28ec71e9c64"}, + {file = "ruff-0.15.22-py3-none-win32.whl", hash = "sha256:e5ba0e4a13fd14abbed2a77b517a3911290c6c6c59ef67784328d1668fab76cf"}, + {file = "ruff-0.15.22-py3-none-win_amd64.whl", hash = "sha256:9be63ba1eb936acd2d1342fb8337c356353706fce233b2a15a09a97037e6acde"}, + {file = "ruff-0.15.22-py3-none-win_arm64.whl", hash = "sha256:e1168075b72158510839f250027659cdd78476f40507dd517892304c41318661"}, + {file = "ruff-0.15.22.tar.gz", hash = "sha256:3f15175b1fb580126f58285a5dae6b2ea89000136d980c64499211f116b54809"}, ] [[package]] @@ -5074,7 +5085,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev", "test"] +groups = ["main", "test"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -5464,22 +5475,22 @@ telegram = ["requests"] [[package]] name = "typer" -version = "0.16.0" +version = "0.26.8" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855"}, - {file = "typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b"}, + {file = "typer-0.26.8-py3-none-any.whl", hash = "sha256:3512ca79ac5c11113414b36e80281b872884477722440691c89d1112e321a49c"}, + {file = "typer-0.26.8.tar.gz", hash = "sha256:c244a6bd558886fe3f8780efb6bdd28bb9aff005a94eedebaa5cb32926fe2f7e"}, ] markers = {main = "(extra == \"crewai\" or extra == \"all\") and python_version <= \"3.13\""} [package.dependencies] -click = ">=8.0.0" -rich = ">=10.11.0" +annotated-doc = ">=0.0.2" +colorama = {version = "*", markers = "platform_system == \"Windows\""} +rich = ">=13.8.0" shellingham = ">=1.3.0" -typing-extensions = ">=3.7.4.3" [[package]] name = "types-requests" @@ -6537,4 +6548,4 @@ otel = ["grpcio", "opentelemetry-api", "opentelemetry-exporter-otlp", "opentelem [metadata] lock-version = "2.1" python-versions = "^3.11,<3.15" -content-hash = "96b393f6ccf730ae5d7a78ca817ccfaec873557609998198cb4ee8598957caed" +content-hash = "bfa462573e7c9ddea1356e75c25ef702db141b6602699e3ac5462af0439db767" diff --git a/pyproject.toml b/pyproject.toml index c22bdd51..aee4ba6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,8 +80,8 @@ mypy = "^1.16.0" invoke = "^2.2.0" openai = ">=2.8.0,<3.0.0" fastapi = "^0.115.0" -ruff = "^0.12.3" -openapi-python-client = "^0.26.1" +ruff = "^0.15.22" +openapi-python-client = "^0.29.0" yq = "^3.4.3" pyyaml = "^6.0.2" pytest-timeout = "^2.4.0" From 2775d7bd77d7e8e2da4bd42c4aa277973a501228 Mon Sep 17 00:00:00 2001 From: etserend Date: Thu, 16 Jul 2026 18:40:02 -0500 Subject: [PATCH 2/3] fix(scripts): update patch_http_validation_error.py regex for openapi-python-client 0.29.x output (HYBIM-777) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0.26.x → 0.29.x upgrade changed the generated http_validation_error.py from_dict body structure: field init and loop ordering changed, and the guard changed from `_detail or []` to `if _detail is not UNSET`. Update _LOOP_RE and _loop_replacement to match the new pattern so the post-gen hook succeeds. Also apply ruff UP-rule auto-fixes (StrEnum, dt.UTC, import ordering) that the bumped ruff 0.15.22 now flags. Co-Authored-By: Claude Opus 4.7 --- scripts/patch_http_validation_error.py | 28 +++++++++++-------- src/splunk_ao/constants/routes.py | 4 +-- src/splunk_ao/experiment.py | 2 +- src/splunk_ao/experiments.py | 4 +-- .../handlers/agent_control/bridge.py | 6 ++-- src/splunk_ao/handlers/base_handler.py | 4 +-- .../handlers/openai_agents/handler.py | 8 +++--- src/splunk_ao/logger/control.py | 12 ++++---- src/splunk_ao/schema/handlers.py | 4 +-- src/splunk_ao/schema/metrics.py | 4 +-- src/splunk_ao/schema/trace.py | 8 +++--- src/splunk_ao/search.py | 4 +-- src/splunk_ao/utils/__init__.py | 4 +-- src/splunk_ao/utils/serialization.py | 2 +- 14 files changed, 49 insertions(+), 45 deletions(-) diff --git a/scripts/patch_http_validation_error.py b/scripts/patch_http_validation_error.py index 6619bafc..836972d0 100644 --- a/scripts/patch_http_validation_error.py +++ b/scripts/patch_http_validation_error.py @@ -37,25 +37,29 @@ # Patterns to find in the auto-generated file # --------------------------------------------------------------------------- -# Inside from_dict — bare initialisation + for-loop produced by the generator: +# Inside from_dict — pattern produced by the generator (openapi-python-client 0.29+): # -# detail = [] # _detail = d.pop("detail", UNSET) -# for detail_item_data in _detail or []: -# detail_item = ValidationError.from_dict(detail_item_data) +# detail: list[ValidationError] | Unset = UNSET +# if _detail is not UNSET: +# detail = [] +# for detail_item_data in _detail: +# detail_item = ValidationError.from_dict(detail_item_data) # <- blank line -# detail.append(detail_item) +# detail.append(detail_item) # # The class-level field annotation already comes out as -# `Union[Unset, list["ValidationError"]] = UNSET` from the generator, so it +# `list[ValidationError] | Unset = UNSET` from the generator, so it # does NOT need to be patched — only the from_dict body is rewritten here. _LOOP_RE = re.compile( - r"(?P[ \t]+)detail = \[\]\n" - r"(?P=indent)_detail = d\.pop\(\"detail\", UNSET\)\n" - r"(?P=indent)for detail_item_data in _detail or \[\]:\n" - r"(?P=indent) detail_item = ValidationError\.from_dict\(detail_item_data\)\n" + r"(?P[ \t]+)_detail = d\.pop\(\"detail\", UNSET\)\n" + r"(?P=indent)detail: list\[ValidationError\] \| Unset = UNSET\n" + r"(?P=indent)if _detail is not UNSET:\n" + r"(?P=indent) detail = \[\]\n" + r"(?P=indent) for detail_item_data in _detail:\n" + r"(?P=indent) detail_item = ValidationError\.from_dict\(detail_item_data\)\n" r"[ \t]*\n" - r"(?P=indent) detail\.append\(detail_item\)", + r"(?P=indent) detail\.append\(detail_item\)", re.MULTILINE, ) @@ -65,8 +69,8 @@ def _loop_replacement(indent: str) -> str: i4 = indent + " " return "\n".join( [ - f"{i}detail: Union[Unset, list[ValidationError]] = UNSET", f'{i}_detail = d.pop("detail", UNSET)', + f"{i}detail: list[ValidationError] | Unset = UNSET", f"{i}if isinstance(_detail, list):", f"{i4}detail = [ValidationError.from_dict(item) for item in _detail]", f"{i}elif isinstance(_detail, str) and _detail:", diff --git a/src/splunk_ao/constants/routes.py b/src/splunk_ao/constants/routes.py index e2b6040d..01ae0ab7 100644 --- a/src/splunk_ao/constants/routes.py +++ b/src/splunk_ao/constants/routes.py @@ -1,7 +1,7 @@ -from enum import Enum +from enum import StrEnum -class Routes(str, Enum): +class Routes(StrEnum): healthcheck = "healthcheck" login = "login" api_key_login = "login/api_key" diff --git a/src/splunk_ao/experiment.py b/src/splunk_ao/experiment.py index 07616946..3f579818 100644 --- a/src/splunk_ao/experiment.py +++ b/src/splunk_ao/experiment.py @@ -429,7 +429,7 @@ def create(self) -> Experiment: if existing_experiment: _logger.warning(f"Experiment {existing_experiment.name} already exists, adding a timestamp") - now = datetime.datetime.now(datetime.timezone.utc) + now = datetime.datetime.now(datetime.UTC) self.name = f"{existing_experiment.name} {now:%Y-%m-%d} at {now:%H:%M:%S}.{now.microsecond // 1000:03d}" # Resolve prompt template before create (needed for trigger=True) diff --git a/src/splunk_ao/experiments.py b/src/splunk_ao/experiments.py index 4f5f1c0a..05436d97 100644 --- a/src/splunk_ao/experiments.py +++ b/src/splunk_ao/experiments.py @@ -11,7 +11,7 @@ from galileo_core.constants.request_method import RequestMethod from splunk_ao.config import SplunkAOConfig from splunk_ao.datasets import Dataset, convert_dataset_row_to_record -from splunk_ao.decorator import splunk_ao_context, splunk_ao_dataset_context, log +from splunk_ao.decorator import log, splunk_ao_context, splunk_ao_dataset_context from splunk_ao.experiment_tags import upsert_experiment_tag from splunk_ao.projects import Project, Projects from splunk_ao.prompts import PromptTemplate @@ -424,7 +424,7 @@ def run_experiment( if existing_experiment: logging.warning(f"Experiment {existing_experiment.name} already exists, adding a timestamp") - now = datetime.datetime.now(datetime.timezone.utc) + now = datetime.datetime.now(datetime.UTC) experiment_name = f"{existing_experiment.name} {now:%Y-%m-%d} at {now:%H:%M:%S}.{now.microsecond // 1000:03d}" # Execute a runner function experiment (custom function flow — uses logstream pipeline) diff --git a/src/splunk_ao/handlers/agent_control/bridge.py b/src/splunk_ao/handlers/agent_control/bridge.py index 1da1190b..e638983b 100644 --- a/src/splunk_ao/handlers/agent_control/bridge.py +++ b/src/splunk_ao/handlers/agent_control/bridge.py @@ -5,7 +5,7 @@ import threading import uuid from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import UTC, datetime from types import ModuleType from typing import Any @@ -53,9 +53,9 @@ def _load_agent_control_modules() -> _AgentControlModules: def _normalize_datetime(value: Any) -> datetime: if isinstance(value, datetime): if value.tzinfo is None: - return value.replace(tzinfo=timezone.utc) + return value.replace(tzinfo=UTC) return value - return datetime.now(tz=timezone.utc) + return datetime.now(tz=UTC) def _duration_ms_to_ns(value: Any) -> int | None: diff --git a/src/splunk_ao/handlers/base_handler.py b/src/splunk_ao/handlers/base_handler.py index 65a22f91..ccdaf267 100644 --- a/src/splunk_ao/handlers/base_handler.py +++ b/src/splunk_ao/handlers/base_handler.py @@ -1,7 +1,7 @@ import logging import time from collections.abc import Callable -from datetime import datetime, timezone +from datetime import UTC, datetime from typing import Any from uuid import UUID @@ -257,7 +257,7 @@ def start_node(self, node_type: NODE_TYPE, parent_run_id: UUID | None, run_id: U node.span_params["start_time"] = time.perf_counter_ns() if "created_at" not in node.span_params: - node.span_params["created_at"] = datetime.now(tz=timezone.utc) + node.span_params["created_at"] = datetime.now(tz=UTC) found_node = self._nodes.get(node_id) if found_node: diff --git a/src/splunk_ao/handlers/openai_agents/handler.py b/src/splunk_ao/handlers/openai_agents/handler.py index e34a8032..415203ea 100644 --- a/src/splunk_ao/handlers/openai_agents/handler.py +++ b/src/splunk_ao/handlers/openai_agents/handler.py @@ -1,6 +1,6 @@ import logging import uuid -from datetime import datetime, timezone +from datetime import UTC, datetime from typing import Any, cast from agents import Span, Trace, TracingProcessor @@ -66,7 +66,7 @@ def on_trace_start(self, trace: Trace) -> None: run_id=trace.trace_id, span_params={ "start_time": _get_timestamp(), - "start_time_iso": datetime.now(timezone.utc).isoformat(), + "start_time_iso": datetime.now(UTC).isoformat(), "name": trace.name, "metadata": convert_to_string_dict(trace.metadata), }, @@ -242,7 +242,7 @@ def on_span_start(self, span: Span[Any]) -> None: # Extract initial data based on type initial_params: dict[str, Any] = { "name": span_name, - "start_time_iso": span.started_at or datetime.now(timezone.utc).isoformat(), + "start_time_iso": span.started_at or datetime.now(UTC).isoformat(), } if splunk_ao_type in ["llm", "chat"]: llm_data = _extract_llm_data(span.span_data) @@ -316,7 +316,7 @@ def on_span_end(self, span: Span[Any]) -> None: # Update node with final data splunk_ao_type = node.node_type - end_params: dict[str, Any] = {"end_time_iso": span.ended_at or datetime.now(timezone.utc).isoformat()} + end_params: dict[str, Any] = {"end_time_iso": span.ended_at or datetime.now(UTC).isoformat()} end_params["duration_ns"] = convert_time_delta_to_ns( datetime.fromisoformat(span.ended_at) - datetime.fromisoformat(node.span_params["start_time_iso"]) ) diff --git a/src/splunk_ao/logger/control.py b/src/splunk_ao/logger/control.py index 34893aff..59cef78f 100644 --- a/src/splunk_ao/logger/control.py +++ b/src/splunk_ao/logger/control.py @@ -1,7 +1,7 @@ from __future__ import annotations -from datetime import datetime, timezone -from enum import Enum +from datetime import UTC, datetime +from enum import StrEnum from typing import Any, Literal from uuid import UUID @@ -17,15 +17,15 @@ except ImportError: HAS_NATIVE_CONTROL_SPAN = False - class ControlAppliesTo(str, Enum): + class ControlAppliesTo(StrEnum): llm_call = "llm_call" tool_call = "tool_call" - class ControlCheckStage(str, Enum): + class ControlCheckStage(StrEnum): pre = "pre" post = "post" - class ControlAction(str, Enum): + class ControlAction(StrEnum): deny = "deny" steer = "steer" observe = "observe" @@ -55,7 +55,7 @@ class ControlSpan(BaseModel): ) name: str = Field(default="control", description="Human-readable control name.") created_at: datetime = Field( - default_factory=lambda: datetime.now(tz=timezone.utc), description="Timestamp of the control execution." + default_factory=lambda: datetime.now(tz=UTC), description="Timestamp of the control execution." ) user_metadata: dict[str, str] = Field(default_factory=dict, description="Metadata associated with the span.") tags: list[str] = Field(default_factory=list, description="Tags associated with the span.") diff --git a/src/splunk_ao/schema/handlers.py b/src/splunk_ao/schema/handlers.py index b601633c..a8903ecb 100644 --- a/src/splunk_ao/schema/handlers.py +++ b/src/splunk_ao/schema/handlers.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import Any, Literal from uuid import UUID @@ -8,7 +8,7 @@ INTEGRATION = Literal["langchain", "crewai", "google_adk"] -class NodeType(str, Enum): +class NodeType(StrEnum): AGENT = "agent" CHAIN = "chain" CHAT = "chat" diff --git a/src/splunk_ao/schema/metrics.py b/src/splunk_ao/schema/metrics.py index 27e25025..47bf3b6b 100644 --- a/src/splunk_ao/schema/metrics.py +++ b/src/splunk_ao/schema/metrics.py @@ -1,5 +1,5 @@ from collections.abc import Callable -from enum import Enum +from enum import StrEnum from typing import Any, Generic, TypeVar from pydantic import BaseModel, Field, ValidationError, field_validator @@ -11,7 +11,7 @@ from galileo_core.schemas.shared.metric import MetricValueType -class SplunkAOMetrics(str, Enum): +class SplunkAOMetrics(StrEnum): """Built-in Galileo metric scorers. Values are human-readable UI labels used for scorer lookup via the API. diff --git a/src/splunk_ao/schema/trace.py b/src/splunk_ao/schema/trace.py index f3be6cc4..234f365b 100644 --- a/src/splunk_ao/schema/trace.py +++ b/src/splunk_ao/schema/trace.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import Any, Literal from pydantic import UUID4, BaseModel, Field @@ -10,7 +10,7 @@ SPAN_TYPE = Literal["llm", "retriever", "tool", "workflow", "agent"] -class LoggingMethod(str, Enum): +class LoggingMethod(StrEnum): playground = "playground" python_client = "python_client" typescript_client = "typescript_client" @@ -118,7 +118,7 @@ class SessionCreateResponse(BaseLogStreamOrExperimentModel): log_stream_id: UUID4 | None = Field(default=None, description="Log stream id associated with the session.") -class LogRecordsSearchFilterOperator(str, Enum): +class LogRecordsSearchFilterOperator(StrEnum): eq = "eq" ne = "ne" contains = "contains" @@ -131,7 +131,7 @@ class LogRecordsSearchFilterOperator(str, Enum): between = "between" -class LogRecordsSearchFilterType(str, Enum): +class LogRecordsSearchFilterType(StrEnum): id = "id" date = "date" number = "number" diff --git a/src/splunk_ao/search.py b/src/splunk_ao/search.py index 0eb3c65f..b79cdfc4 100644 --- a/src/splunk_ao/search.py +++ b/src/splunk_ao/search.py @@ -1,5 +1,5 @@ import logging -from enum import Enum +from enum import StrEnum from splunk_ao.config import SplunkAOConfig from splunk_ao.resources.api.trace import ( @@ -18,7 +18,7 @@ logger = logging.getLogger(__name__) -class RecordType(str, Enum): +class RecordType(StrEnum): SPAN = "spans" TRACE = "traces" SESSION = "sessions" diff --git a/src/splunk_ao/utils/__init__.py b/src/splunk_ao/utils/__init__.py index 4cc0e5fe..d00d4f55 100644 --- a/src/splunk_ao/utils/__init__.py +++ b/src/splunk_ao/utils/__init__.py @@ -1,8 +1,8 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime, timezone def _get_timestamp() -> datetime: - return datetime.now(timezone.utc) + return datetime.now(UTC) def _now_ns() -> int: diff --git a/src/splunk_ao/utils/serialization.py b/src/splunk_ao/utils/serialization.py index 4cf69a2e..27dead39 100644 --- a/src/splunk_ao/utils/serialization.py +++ b/src/splunk_ao/utils/serialization.py @@ -112,7 +112,7 @@ def serialize_datetime(v: dt.datetime) -> str: """ def _serialize_zoned_datetime(v: dt.datetime) -> str: - if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.timezone.utc.tzname(None): + if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.UTC.tzname(None): # UTC is a special case where we use "Z" at the end instead of "+00:00" return v.isoformat().replace("+00:00", "Z") # Delegate to the typical +/- offset format From ba2608a7ac5d9d7a9a7f4575db5dd637994cab0f Mon Sep 17 00:00:00 2001 From: etserend Date: Fri, 17 Jul 2026 13:03:38 -0500 Subject: [PATCH 3/3] fix(lint): resolve ruff 0.15.22 errors surfaced by version bump (HYBIM-777) - Remove unused `timezone` import from utils/__init__.py (F401) - Add explicit `__hash__ = None` to schema/message.py (PLW1641) - Add experiment.py and metric.py to per-file-ignores for PLC0415 (local imports are intentional circular-dependency workarounds) Co-Authored-By: Claude Opus 4.7 --- pyproject.toml | 2 ++ src/splunk_ao/schema/message.py | 2 ++ src/splunk_ao/utils/__init__.py | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index aee4ba6e..7a7ea5a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -280,6 +280,8 @@ ignore = [ "src/splunk_ao/project.py" = ["PLC0415"] # Bottom-of-file circular import avoidance "src/splunk_ao/logger/logger.py" = ["PLC0415"] # Local imports to avoid circular dependencies "src/splunk_ao/logger/__init__.py" = ["PLC0415"] # Lazy import for GalileoLogger +"src/splunk_ao/experiment.py" = ["PLC0415"] # Local imports to avoid circular dependencies +"src/splunk_ao/metric.py" = ["PLC0415"] # Local imports to avoid circular dependencies [tool.ruff.lint.isort] known-first-party = ["galileo_core"] diff --git a/src/splunk_ao/schema/message.py b/src/splunk_ao/schema/message.py index bb183ee6..18bf7cb3 100644 --- a/src/splunk_ao/schema/message.py +++ b/src/splunk_ao/schema/message.py @@ -12,6 +12,8 @@ class Message(CoreMessage): + __hash__ = None # type: ignore[assignment] + def to_dict(self) -> dict[str, Any]: return self.model_dump(exclude_none=True) diff --git a/src/splunk_ao/utils/__init__.py b/src/splunk_ao/utils/__init__.py index d00d4f55..cf16c651 100644 --- a/src/splunk_ao/utils/__init__.py +++ b/src/splunk_ao/utils/__init__.py @@ -1,4 +1,4 @@ -from datetime import UTC, datetime, timezone +from datetime import UTC, datetime def _get_timestamp() -> datetime: