From ffe8129ae434e05d6f6a05f6f22741563f6becb7 Mon Sep 17 00:00:00 2001 From: Chandra Kiran G Date: Thu, 13 Aug 2026 11:56:49 +0530 Subject: [PATCH 1/6] chore: Add pre-commit gate, pin linters --- .gitattributes | 18 ++++++++++++++ .pre-commit-config.yaml | 55 +++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 11 ++++++--- Makefile | 15 ++++++----- pyproject.toml | 5 +++- setup.cfg | 22 ++++++++++------- 6 files changed, 107 insertions(+), 19 deletions(-) create mode 100644 .gitattributes create mode 100644 .pre-commit-config.yaml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..e053d0d5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,18 @@ +# Normalise line endings to LF in the repository for all text files, whatever +# the contributor's platform. Without this, a CRLF checkout on Windows lands +# CRLF in commits and black/ruff disagree with CI. +* text=auto eol=lf + +# The vendored OpenAI SDK is generated by python-vendorize. Keep it byte-for-byte +# as emitted (openai-*.dist-info/RECORD ships CRLF), so re-vendoring produces no +# spurious line-ending churn. Consistent with excluding _vendor from all linters. +portkey_ai/_vendor/** -text + +# Binary files must not be normalised. +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.pdf binary +*.whl binary diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..05f17e12 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,55 @@ +# Local pre-commit gate. Mirrors the `pre-commit` CI job exactly, so a clean +# run here is a clean run there. +# +# Setup (once per clone): +# make hooks +# +# Tool versions below must stay in sync with the `dev` extra in setup.cfg. +# Bump them together, in their own PR. + +# The vendored OpenAI SDK is generated by python-vendorize and must never be +# reformatted -- see CLAUDE.md. Excluding it here also keeps pre-commit from +# handing those paths to black/ruff in the first place. +exclude: ^portkey_ai/_vendor/ + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + # This is the hook that would have caught PR #439. + - id: end-of-file-fixer + - id: trailing-whitespace + - id: mixed-line-ending + args: [--fix=lf] + - id: check-yaml + - id: check-toml + - id: check-merge-conflict + - id: check-case-conflict + - id: check-added-large-files + + - repo: https://github.com/psf/black + rev: 23.7.0 + hooks: + - id: black + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.292 + hooks: + - id: ruff + args: [--fix] + + - repo: local + hooks: + # mypy runs as a `system` hook rather than via mirrors-mypy: it needs the + # project's own environment to resolve the vendored openai package and + # pydantic/httpx types, which an isolated hook env would not have. + # Requires `make dev` in the active virtualenv. + - id: mypy + name: mypy + entry: mypy + language: system + types: [python] + # Whole-project run -- mypy's `files` setting in pyproject.toml decides + # the scope, and per-file invocation gives wrong results anyway. + pass_filenames: false + require_serial: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c40748f4..58cf95ad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ Hello and thank you for considering contributing to the Portkey Python SDK! Whet ## 🚀 Quick Start 1. Fork the repository on Github. -2. Clone your forked repository to your machine. +2. Clone your forked repository to your machine. ```sh $ git clone https://github.com/YOUR_USERNAME/portkey-python-sdk.git ``` @@ -15,7 +15,12 @@ $ source .venv/bin/activate # On macOS and Linux ``` 4. Install dependencies ```sh -$ pip install -e . +$ make dev +``` +5. Install the git hooks. Do this once per clone — it is what stops formatting + and typing problems from ever reaching a PR. +```sh +$ make hooks ``` ## 🖋 Types of Contributions @@ -40,4 +45,4 @@ Facing issues or have questions? Don't hesitate to share your doubts or question Releases are made as soon as possible to ensure that new features and fixes reach our users quickly. We follow a seamless CI/CD pipeline to ensure the smooth transition of code from development to production. ## 🎊 Your PR is Merged! -All successful PRs are celebrated on our [Discord](https://discord.com/invite/DD7vgKK299) and are mentioned in the release notes, and significant contributions are highlighted on our [Twitter](https://twitter.com/PortkeyAI). Stay tuned for more bounties and goodies for contributors in the near future! \ No newline at end of file +All successful PRs are celebrated on our [Discord](https://discord.com/invite/DD7vgKK299) and are mentioned in the release notes, and significant contributions are highlighted on our [Twitter](https://twitter.com/PortkeyAI). Stay tuned for more bounties and goodies for contributors in the near future! diff --git a/Makefile b/Makefile index 5a5e70d6..cae508d9 100644 --- a/Makefile +++ b/Makefile @@ -2,21 +2,24 @@ GIT_ROOT ?= $(shell git rev-parse --show-toplevel) help: ## Show all Makefile targets @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[33m%-30s\033[0m %s\n", $$1, $$2}' -.PHONY: format lint +.PHONY: format lint hooks format: ## Run code formatter: black black . ruff check . --fix lint: ## Run linters: mypy, black, ruff - mypy . + mypy black . --check ruff check . +hooks: ## Install the git pre-commit hooks (run once per clone) + pre-commit install + pre-commit run --all-files test: ## Run tests pytest tests watch-docs: ## Build and watch documentation sphinx-autobuild docs/ docs/_build/html --open-browser --watch $(GIT_ROOT)/llama_index/ build: - mypy . + mypy black . --check ruff check . rm -rf dist/ build/ @@ -28,12 +31,12 @@ upload: python -m twine upload dist/portkey_ai-* rm -rf dist -sandbox: +sandbox: python -m pip install twine python -m twine upload --repository testpypi dist/portkey_ai-* rm -rf dist -dev: +dev: pip install -e ".[dev]" langchain_callback: @@ -43,4 +46,4 @@ llama_index_callback: pip install -e ".[llama_index_callback]" instrumentation: - pip install -e ".[instrumentation]" \ No newline at end of file + pip install -e ".[instrumentation]" diff --git a/pyproject.toml b/pyproject.toml index f66aea25..980f01ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,9 @@ requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.mypy] +# Explicit scope. Without this, a bare `mypy .` also type-checks untracked +# scratch files in the repo root, so `make lint` fails locally while CI passes. +files = ['portkey_ai', 'examples'] exclude = ['portkey_ai/_vendor', 'tests'] ignore_missing_imports = true follow_imports = "silent" @@ -18,4 +21,4 @@ force-exclude = '''(portkey_ai/_vendor)/''' [tool.ruff] exclude = ["portkey_ai/_vendor", "tests"] ignore = ["E501"] -line-length = 88 \ No newline at end of file +line-length = 88 diff --git a/setup.cfg b/setup.cfg index 5104283c..e72d5876 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,19 +34,28 @@ console_scripts = portkey_ai = portkey_ai._portkey_scripts:main [options.package_data] - portkey_ai = + portkey_ai = py.typed _vendor/openai/lib/* _vendor/openai/lib/streaming/* [options.extras_require] dev = - mypy>=0.991,<2.0 + # Linters are pinned exactly so that a local run and a CI run are the same + # run. `mypy>=0.991,<2.0` used to resolve to a different version on every + # interpreter (1.14.1 on 3.8, 1.19.1 on 3.9, 1.20.2 on 3.10+), which meant + # `make lint` could pass locally and fail in CI on identical code. + # Bump these deliberately, in their own PR, and update + # .pre-commit-config.yaml to match. + mypy==1.20.2; python_version >= "3.10" + mypy==1.19.1; python_version == "3.9" + mypy==1.14.1; python_version < "3.9" black==23.7.0 pytest==7.4.2 python-dotenv==1.0.0 ruff==0.0.292 pytest-asyncio==0.23.5 + pre-commit==4.3.0; python_version >= "3.9" langchain_callback = langchain-core llama_index_callback = @@ -61,14 +70,9 @@ adk = google-adk google-genai -[mypy] -ignore_missing_imports = true -files = portkey_ai -exclude = portkey_ai/_vendor/* - [options.packages.find] where = . include = portkey_ai* -exclude = +exclude = tests* - tests \ No newline at end of file + tests From b0f2f8f0b1d7aeb85f6df0361c2ec2a738fb7165 Mon Sep 17 00:00:00 2001 From: Chandra Kiran G Date: Thu, 13 Aug 2026 11:59:40 +0530 Subject: [PATCH 2/6] test: reintroduce type error --- portkey_ai/api_resources/apis/responses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/portkey_ai/api_resources/apis/responses.py b/portkey_ai/api_resources/apis/responses.py index 89f698f8..efa52863 100644 --- a/portkey_ai/api_resources/apis/responses.py +++ b/portkey_ai/api_resources/apis/responses.py @@ -339,7 +339,7 @@ def retrieve( timeout = kwargs.pop("timeout", None) if stream is True: - return self.openai_client.responses.retrieve( # type: ignore[return-value] + return self.openai_client.responses.retrieve( response_id=response_id, stream=stream, include=include, @@ -1134,7 +1134,7 @@ async def retrieve( timeout = kwargs.pop("timeout", None) if stream is True: - return await self.openai_client.responses.retrieve( # type: ignore[return-value] + return await self.openai_client.responses.retrieve( response_id=response_id, stream=stream, include=include, From f568b3dfb040f152582231516304db04726f9322 Mon Sep 17 00:00:00 2001 From: Chandra Kiran G Date: Thu, 13 Aug 2026 12:05:39 +0530 Subject: [PATCH 3/6] chore: Harden lint gate with pre-commit and pinned linters --- .github/CODE_OF_CONDUCT.md | 256 ++++++++++++------------- .github/ISSUE_TEMPLATE/BUG_REPORT.yml | 2 +- .github/ISSUE_TEMPLATE/config.yml | 4 +- .github/pull_request_template.md | 2 +- .github/workflows/ci.yml | 37 +++- .gitignore | 2 +- CHANGELOG.md | 3 +- README.md | 8 +- SECURITY.md | 2 +- SUPPORT.md | 8 +- claude.md | 12 +- portkey_ai/api_resources/client.py | 8 +- portkey_ai/api_resources/exceptions.py | 2 +- tests/configs/batches/seed_tasks.jsonl | 2 +- tests/models.json | 4 +- vendorize.toml | 2 +- 16 files changed, 190 insertions(+), 164 deletions(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 507918c6..eb6a8016 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -1,128 +1,128 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -support@portkey.ai. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +support@portkey.ai. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml index 1eefad35..59ae54cc 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -49,4 +49,4 @@ body: description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com) options: - label: I agree to follow this project's Code of Conduct - required: true \ No newline at end of file + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 41dc895f..df0d4307 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,5 +4,5 @@ contact_links: url: https://discord.com/invite/DD7vgKK299 about: Please ask and answer questions here. - name: Portkey Bounty - url: https://discord.com/invite/DD7vgKK299 - about: Please report security vulnerabilities here. \ No newline at end of file + url: https://discord.com/invite/DD7vgKK299 + about: Please report security vulnerabilities here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 3f7a95e5..5d5fb25b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -9,4 +9,4 @@ **Related Issues:** -# \ No newline at end of file +# diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59dd7a99..eb83f09e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,25 +9,52 @@ on: branches: - main - dev - + # Allows you to run this workflow manually from the Actions tab workflow_dispatch: jobs: - + + # Authoritative lint gate: runs the exact same pinned hooks that + # `make hooks` runs on a contributor's machine, on a single pinned + # interpreter. Make this a required status check on `main`. + pre-commit: + name: Lint (pre-commit) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - uses: actions/cache@v4 + with: + path: ~/.cache/pre-commit + key: ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + make dev + + - name: Run pre-commit + run: pre-commit run --all-files --show-diff-on-failure + Linting: runs-on: ubuntu-latest strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11'] - + steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - + - uses: actions/cache@v4 with: path: ~/.cache/pip @@ -40,4 +67,4 @@ jobs: - name: Lint with mypy, black and ruff run: | - make lint \ No newline at end of file + make lint diff --git a/.gitignore b/.gitignore index 536df730..3d4b047f 100644 --- a/.gitignore +++ b/.gitignore @@ -160,4 +160,4 @@ cython_debug/ #.idea/ .vscode/ -.DS_Store \ No newline at end of file +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index 415eaac1..b1beb099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,11 +61,10 @@ We are excited to announce the **stable release** of the all-new **Portkey Pytho - **Stability and Reliability**: This release marks the stable version of Portkey Python SDK, thoroughly tested to ensure reliable performance in your projects. -- **Ease of Use**: The SDK follows OpenAI SDK footprint, and with one line of change to your existing code, you can add Portkey's production features to your app. +- **Ease of Use**: The SDK follows OpenAI SDK footprint, and with one line of change to your existing code, you can add Portkey's production features to your app. - **Community Support**: [Join our growing community](https://discord.gg/QHJ3RgcvKT) of practitioners putting LLMs in production. Share ideas, resolve doubts, and collaborate on projects. Happy coding! - The Portkey Team - diff --git a/README.md b/README.md index 2441d66d..70f87f43 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The Portkey SDK is built on top of the OpenAI SDK, allowing you to seamlessly in Analytics
Track your app & LLM's performance with 40+ production-critical metrics in a single place. - + ## Usage @@ -117,7 +117,7 @@ from portkey_ai.integrations.strands import PortkeyStrands model = PortkeyStrands( api_key="PORTKEY_API_KEY", model_id="@openai/gpt-4o-mini", -# base_url="https://api.portkey.ai/v1", ## Optional +# base_url="https://api.portkey.ai/v1", ## Optional ) agent = Agent(model=model) @@ -150,7 +150,7 @@ from portkey_ai.integrations.adk import PortkeyAdk llm = PortkeyAdk( api_key="PORTKEY_API_KEY", model="@openai/gpt-4o-mini", -# base_url="https://api.portkey.ai/v1", ## Optional +# base_url="https://api.portkey.ai/v1", ## Optional ) req = LlmRequest( @@ -213,7 +213,7 @@ asyncio.run(main()) Configuration notes: - **system_role**: By default, the adapter sends the system instruction as a `developer` role message to align with ADK. If your provider expects a strict `system` role, pass `system_role="system"` when constructing `PortkeyAdk`. - + ```python llm = PortkeyAdk( model="@openai/gpt-4o-mini", diff --git a/SECURITY.md b/SECURITY.md index 82c18a93..0fb3b543 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,4 +8,4 @@ ## Reporting a Vulnerability -Please report any security vulnerabilities at `support@portkey.ai`. +Please report any security vulnerabilities at `support@portkey.ai`. diff --git a/SUPPORT.md b/SUPPORT.md index 6c200508..af1b4cae 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,7 +1,7 @@ -## How to file issues and get help +## How to file issues and get help -This project uses GitHub Issues to track bugs and feature requests. Please search the existing -issues before filing new issues to avoid duplicates. For new issues, file your bug or +This project uses GitHub Issues to track bugs and feature requests. Please search the existing +issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new Issue. -For help and questions about using this project, please contact `support@portkey.ai`. Join the community discussions [here](https://discord.com/invite/DD7vgKK299). \ No newline at end of file +For help and questions about using this project, please contact `support@portkey.ai`. Join the community discussions [here](https://discord.com/invite/DD7vgKK299). diff --git a/claude.md b/claude.md index 02654ceb..7e428265 100644 --- a/claude.md +++ b/claude.md @@ -139,14 +139,14 @@ class Portkey(APIClient): def __init__(self, *, api_key, base_url, virtual_key, config, ...): # Initialize base client with headers super().__init__(...) - + # Create vendored OpenAI client pointing to Portkey gateway self.openai_client = OpenAI( api_key=OPEN_AI_API_KEY, # Placeholder key base_url=self.base_url, # Portkey gateway URL default_headers=self.allHeaders, ) - + # Initialize all API resources self.completions = apis.Completion(self) self.chat = apis.ChatCompletion(self) @@ -223,7 +223,7 @@ def create( # Use Omit for params that should be omitted when not provided expires_after: Union[ExpiresAfter, Omit] = omit, file_ids: Union[List[str], Omit] = omit, - + # Use NotGiven for params where None is a valid, distinct value # e.g., timeout=None means "no timeout", timeout=NOT_GIVEN means "use default" timeout: Union[float, httpx.Timeout, None, NotGiven] = NOT_GIVEN, @@ -270,7 +270,7 @@ def create(self, *, name: str, **kwargs): extra_query = kwargs.pop("extra_query", None) extra_body = kwargs.pop("extra_body", None) timeout = kwargs.pop("timeout", None) - + # Merge remaining kwargs into extra_body user_extra_body = extra_body or {} merged_extra_body = {**user_extra_body, **kwargs} @@ -445,7 +445,7 @@ The tool rewrites imports from `openai.*` to `portkey_ai._vendor.openai.*` ``` 2. **`portkey_ai/_vendor/openai/_base_client.py`** - + Replace the `_should_retry` method with Portkey's custom logic: ```python def _should_retry(self, response: httpx.Response) -> bool: @@ -512,7 +512,7 @@ def new_method( extra_query = kwargs.pop("extra_query", None) extra_body = kwargs.pop("extra_body", None) timeout = kwargs.pop("timeout", None) - + response = self.openai_client.with_raw_response.resource.new_method( param=param, extra_headers=extra_headers, diff --git a/portkey_ai/api_resources/client.py b/portkey_ai/api_resources/client.py index 4558d2a3..c85b7094 100644 --- a/portkey_ai/api_resources/client.py +++ b/portkey_ai/api_resources/client.py @@ -211,8 +211,8 @@ def __init__( ) except ImportError: raise ImportError( - """Please install opentelemetry for instrumentation, - you can use `pip install 'portkey-ai[instrumentation]'` + """Please install opentelemetry for instrumentation, + you can use `pip install 'portkey-ai[instrumentation]'` to install""" ) initialize_instrumentation(api_key=self.api_key, base_url=self.base_url) @@ -557,8 +557,8 @@ def __init__( ) except ImportError: raise ImportError( - """Please install opentelemetry for instrumentation, - you can use `pip install 'portkey-ai[instrumentation]'` + """Please install opentelemetry for instrumentation, + you can use `pip install 'portkey-ai[instrumentation]'` to install""" ) initialize_instrumentation(api_key=self.api_key, base_url=self.base_url) diff --git a/portkey_ai/api_resources/exceptions.py b/portkey_ai/api_resources/exceptions.py index 4a3a185e..01fe0be8 100644 --- a/portkey_ai/api_resources/exceptions.py +++ b/portkey_ai/api_resources/exceptions.py @@ -32,7 +32,7 @@ class APIStatusError(APIError): body: object """The API response body. - If the API responded with a valid JSON structure then this property will be the + If the API responded with a valid JSON structure then this property will be the decoded result. If it isn't a valid JSON structure then this will be the raw response. """ diff --git a/tests/configs/batches/seed_tasks.jsonl b/tests/configs/batches/seed_tasks.jsonl index 35f42792..8755b1cc 100644 --- a/tests/configs/batches/seed_tasks.jsonl +++ b/tests/configs/batches/seed_tasks.jsonl @@ -18,4 +18,4 @@ {"id": "seed_task_18", "name": "python_summation", "instruction": "Write a Python function that takes two numbers as input and returns their sum.", "instances": [{"input": "5, 7", "output": "def add_numbers(a, b):\n return a + b\n\nresult = add_numbers(5, 7)\nprint(result)"}], "is_classification": false} {"id": "seed_task_19", "name": "java_loop_array", "instruction": "Create a JavaScript function that takes an array of numbers and returns the product of all elements.", "instances": [{"input": "[2, 3, 4]", "output": "function multiplyArrayElements(arr) {\n let product = 1;\n for (const num of arr) {\n product *= num;\n }\n return product;\n}\n\nconst result = multiplyArrayElements([2, 3, 4]);\nconsole.log(result);"}], "is_classification": false} {"id": "seed_task_20", "name": "shell_total_lines_in_txt_file", "instruction": "Can you provide a shell script that displays the total number of lines in all '*.txt' files in the current directory?", "instances": [{"input": "\"file1.txt:\\nHello\\nWorld\\n\\nfile2.txt:\\nAnother\\nExample\"", "output": "#!/bin/sh\n\ntotal_lines=0\n\nfor file in *.txt; do\n lines=$(wc -l < \"$file\")\n total_lines=$((total_lines + lines))\ndone\n\necho \"Total lines: $total_lines\""}], "is_classification": false} -{"id": "seed_task_21", "name": "java_reverse_string_no_builtin", "instruction": "Implement a Java method to reverse a string without using any built-in functions.", "instances": [{"input": "\"Hello, World!\"", "output": "public class StringReversal {\n public static String reverseString(String input) {\n char[] charArray = input.toCharArray();\n int left = 0;\n int right = charArray.length - 1;\n\n while (left < right) {\n char temp = charArray[left];\n charArray[left] = charArray[right];\n charArray[right] = temp;\n\n left++;\n right--;\n }\n return new String(charArray);\n }\n\n public static void main(String[] args) {\n String str = \"Hello, World!\";\n System.out.println(\"Reversed string: \" + reverseString(str));\n }\n}"}], "is_classification": false} \ No newline at end of file +{"id": "seed_task_21", "name": "java_reverse_string_no_builtin", "instruction": "Implement a Java method to reverse a string without using any built-in functions.", "instances": [{"input": "\"Hello, World!\"", "output": "public class StringReversal {\n public static String reverseString(String input) {\n char[] charArray = input.toCharArray();\n int left = 0;\n int right = charArray.length - 1;\n\n while (left < right) {\n char temp = charArray[left];\n charArray[left] = charArray[right];\n charArray[right] = temp;\n\n left++;\n right--;\n }\n return new String(charArray);\n }\n\n public static void main(String[] args) {\n String str = \"Hello, World!\";\n System.out.println(\"Reversed string: \" + reverseString(str));\n }\n}"}], "is_classification": false} diff --git a/tests/models.json b/tests/models.json index 73033dc7..e6126a09 100644 --- a/tests/models.json +++ b/tests/models.json @@ -57,7 +57,7 @@ "claude-2.1", "claude-2.0", "claude-instant-1.2" - ], + ], "image":[], "audio":[] }, @@ -111,4 +111,4 @@ "image":[], "audio":[] } -} \ No newline at end of file +} diff --git a/vendorize.toml b/vendorize.toml index 9e1a1473..1d78823f 100644 --- a/vendorize.toml +++ b/vendorize.toml @@ -1,4 +1,4 @@ target = "portkey_ai/_vendor" packages = [ "openai==2.30.0" -] \ No newline at end of file +] From 7632bbe8aa9a797cfc29fb54f4e2db03dab0519a Mon Sep 17 00:00:00 2001 From: Chandra Kiran G Date: Thu, 13 Aug 2026 12:21:09 +0530 Subject: [PATCH 4/6] chore: Fix linting issue --- portkey_ai/api_resources/apis/responses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/portkey_ai/api_resources/apis/responses.py b/portkey_ai/api_resources/apis/responses.py index efa52863..89f698f8 100644 --- a/portkey_ai/api_resources/apis/responses.py +++ b/portkey_ai/api_resources/apis/responses.py @@ -339,7 +339,7 @@ def retrieve( timeout = kwargs.pop("timeout", None) if stream is True: - return self.openai_client.responses.retrieve( + return self.openai_client.responses.retrieve( # type: ignore[return-value] response_id=response_id, stream=stream, include=include, @@ -1134,7 +1134,7 @@ async def retrieve( timeout = kwargs.pop("timeout", None) if stream is True: - return await self.openai_client.responses.retrieve( + return await self.openai_client.responses.retrieve( # type: ignore[return-value] response_id=response_id, stream=stream, include=include, From 1414b2c22450ea7336a16a5529ded07203b7ba3e Mon Sep 17 00:00:00 2001 From: Chandra Kiran G Date: Thu, 13 Aug 2026 12:32:44 +0530 Subject: [PATCH 5/6] chore: Use Ruff for both linting and formatting --- .github/workflows/ci.yml | 2 +- .pre-commit-config.yaml | 16 ++-- Makefile | 21 +++-- claude.md | 9 +- portkey_ai/_portkey_scripts.py | 1 + portkey_ai/api_resources/__init__.py | 1 + portkey_ai/api_resources/apis/assistants.py | 12 +-- portkey_ai/api_resources/apis/embeddings.py | 4 +- portkey_ai/api_resources/apis/fine_tuning.py | 10 +-- portkey_ai/api_resources/apis/generation.py | 18 ++-- portkey_ai/api_resources/apis/images.py | 76 +++++++--------- portkey_ai/api_resources/apis/moderations.py | 4 +- portkey_ai/api_resources/apis/post.py | 18 ++-- portkey_ai/api_resources/apis/responses.py | 48 ++++------ portkey_ai/api_resources/apis/threads.py | 36 ++++---- .../api_resources/apis/vector_stores.py | 38 ++++---- portkey_ai/api_resources/base_client.py | 90 +++++++------------ portkey_ai/api_resources/streaming.py | 16 ++-- portkey_ai/api_resources/utils.py | 11 +-- .../portkey_langchain_callback_handler.py | 38 +++++--- portkey_ai/llms/llama_index/utils.py | 3 +- pyproject.toml | 18 ++-- setup.cfg | 4 +- 23 files changed, 229 insertions(+), 265 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb83f09e..69887c04 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,6 @@ jobs: python -m pip install --upgrade pip make dev - - name: Lint with mypy, black and ruff + - name: Lint with mypy and ruff run: | make lint diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 05f17e12..26ab544e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ # The vendored OpenAI SDK is generated by python-vendorize and must never be # reformatted -- see CLAUDE.md. Excluding it here also keeps pre-commit from -# handing those paths to black/ruff in the first place. +# handing those paths to ruff in the first place. exclude: ^portkey_ai/_vendor/ repos: @@ -27,16 +27,16 @@ repos: - id: check-case-conflict - id: check-added-large-files - - repo: https://github.com/psf/black - rev: 23.7.0 - hooks: - - id: black - + # ruff is both the linter and the formatter -- black is deliberately absent. + # Do not add black back alongside `ruff-format`: they disagree on ~20 files + # and would revert each other on every run, so the hook would never converge. + # Order matters: lint fixes first, then format the result. - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.292 + rev: v0.16.2 hooks: - - id: ruff + - id: ruff-check args: [--fix] + - id: ruff-format - repo: local hooks: diff --git a/Makefile b/Makefile index cae508d9..5da751f7 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,18 @@ help: ## Show all Makefile targets @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[33m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: format lint hooks -format: ## Run code formatter: black - black . - ruff check . --fix -lint: ## Run linters: mypy, black, ruff +# Same scope as mypy's `files` in pyproject.toml. Passing `.` would also pick up +# untracked scratch files in the repo root, so `make lint` would fail locally +# while CI passes on the identical commit. +LINT_PATHS = portkey_ai examples + +format: ## Run code formatter: ruff + ruff check $(LINT_PATHS) --fix + ruff format $(LINT_PATHS) +lint: ## Run linters: mypy, ruff mypy - black . --check - ruff check . + ruff format $(LINT_PATHS) --check + ruff check $(LINT_PATHS) hooks: ## Install the git pre-commit hooks (run once per clone) pre-commit install pre-commit run --all-files @@ -20,8 +25,8 @@ watch-docs: ## Build and watch documentation build: mypy - black . --check - ruff check . + ruff format $(LINT_PATHS) --check + ruff check $(LINT_PATHS) rm -rf dist/ build/ python -m pip install build python -m build . diff --git a/claude.md b/claude.md index 7e428265..c8a0f871 100644 --- a/claude.md +++ b/claude.md @@ -82,13 +82,14 @@ exclude = ['portkey_ai/_vendor', 'tests'] module = 'portkey_ai._vendor.*' ignore_errors = true -[tool.black] -force-exclude = '''(portkey_ai/_vendor)/''' - [tool.ruff] -exclude = ["portkey_ai/_vendor", "tests"] +exclude = ["portkey_ai/_vendor", "tests", "*.md"] ``` +ruff is both the linter (`ruff check`) and the formatter (`ruff format`); black is +no longer used. `.pre-commit-config.yaml` also excludes `^portkey_ai/_vendor/` +globally, so the hooks never receive vendored paths at all. + #### 4. Type Reuse vs Redefinition **Response types** - OpenAI types are imported directly for nested types: ```python diff --git a/portkey_ai/_portkey_scripts.py b/portkey_ai/_portkey_scripts.py index 14107e72..bafccdab 100644 --- a/portkey_ai/_portkey_scripts.py +++ b/portkey_ai/_portkey_scripts.py @@ -1,4 +1,5 @@ """main file""" + import argparse from .version import VERSION diff --git a/portkey_ai/api_resources/__init__.py b/portkey_ai/api_resources/__init__.py index 059dc6ef..01116808 100644 --- a/portkey_ai/api_resources/__init__.py +++ b/portkey_ai/api_resources/__init__.py @@ -1,4 +1,5 @@ """""" + from .apis import ( Completion, AsyncCompletion, diff --git a/portkey_ai/api_resources/apis/assistants.py b/portkey_ai/api_resources/apis/assistants.py index 838eaf77..b31ed897 100644 --- a/portkey_ai/api_resources/apis/assistants.py +++ b/portkey_ai/api_resources/apis/assistants.py @@ -28,7 +28,7 @@ def create( tool_resources: Union[Any, Omit] = omit, tools: Union[Any, Omit] = omit, top_p: Union[float, Omit] = omit, - **kwargs + **kwargs, ) -> Assistant: response = self.openai_client.with_raw_response.beta.assistants.create( model=model, @@ -76,7 +76,7 @@ def update( tool_resources: Union[Any, Omit] = omit, tools: Union[Any, Omit] = omit, top_p: Union[float, Omit] = omit, - **kwargs + **kwargs, ) -> Assistant: response = self.openai_client.with_raw_response.beta.assistants.update( assistant_id=assistant_id, @@ -104,7 +104,7 @@ def list( before: Union[str, Omit] = omit, limit: Union[int, Omit] = omit, order: Union[Omit, Literal["asc", "desc"]] = omit, - **kwargs + **kwargs, ) -> AssistantList: response = self.openai_client.with_raw_response.beta.assistants.list( after=after, before=before, limit=limit, order=order @@ -141,7 +141,7 @@ async def create( tool_resources: Union[Any, Omit] = omit, tools: Union[Any, Omit] = omit, top_p: Union[float, Omit] = omit, - **kwargs + **kwargs, ) -> Assistant: response = await self.openai_client.with_raw_response.beta.assistants.create( model=model, @@ -193,7 +193,7 @@ async def update( tool_resources: Union[Any, Omit] = omit, tools: Union[Any, Omit] = omit, top_p: Union[float, Omit] = omit, - **kwargs + **kwargs, ) -> Assistant: response = await self.openai_client.with_raw_response.beta.assistants.update( assistant_id=assistant_id, @@ -221,7 +221,7 @@ async def list( before: Union[str, Omit] = omit, limit: Union[int, Omit] = omit, order: Union[Omit, Literal["asc", "desc"]] = omit, - **kwargs + **kwargs, ) -> AssistantList: response = await self.openai_client.with_raw_response.beta.assistants.list( after=after, before=before, limit=limit, order=order diff --git a/portkey_ai/api_resources/apis/embeddings.py b/portkey_ai/api_resources/apis/embeddings.py index 13bb9c5f..8235cb44 100644 --- a/portkey_ai/api_resources/apis/embeddings.py +++ b/portkey_ai/api_resources/apis/embeddings.py @@ -21,7 +21,7 @@ def create( dimensions: Union[int, NotGiven] = NOT_GIVEN, encoding_format: Union[str, NotGiven] = NOT_GIVEN, user: Union[str, NotGiven] = NOT_GIVEN, - **kwargs + **kwargs, ) -> CreateEmbeddingResponse: response = self.openai_client.with_raw_response.embeddings.create( input=input, @@ -52,7 +52,7 @@ async def create( dimensions: Union[int, NotGiven] = NOT_GIVEN, encoding_format: Union[str, NotGiven] = NOT_GIVEN, user: Union[str, NotGiven] = NOT_GIVEN, - **kwargs + **kwargs, ) -> CreateEmbeddingResponse: response = await self.openai_client.with_raw_response.embeddings.create( input=input, diff --git a/portkey_ai/api_resources/apis/fine_tuning.py b/portkey_ai/api_resources/apis/fine_tuning.py index 0d3679e1..f7d65389 100644 --- a/portkey_ai/api_resources/apis/fine_tuning.py +++ b/portkey_ai/api_resources/apis/fine_tuning.py @@ -574,12 +574,10 @@ async def validate( grader: grader_run_params.Grader, **kwargs, ) -> GraderValidateResponse: - response = ( - await ( - self.openai_client.with_raw_response.fine_tuning.alpha.graders.validate( - grader=grader, - extra_body=kwargs, - ) + response = await ( + self.openai_client.with_raw_response.fine_tuning.alpha.graders.validate( + grader=grader, + extra_body=kwargs, ) ) data = GraderValidateResponse(**json.loads(response.text)) diff --git a/portkey_ai/api_resources/apis/generation.py b/portkey_ai/api_resources/apis/generation.py index 0015f1f4..95e66d5a 100644 --- a/portkey_ai/api_resources/apis/generation.py +++ b/portkey_ai/api_resources/apis/generation.py @@ -491,8 +491,7 @@ def create( top_p: Union[float, NotGiven] = NOT_GIVEN, extra_headers: Mapping[str, str] = {}, **kwargs, - ) -> Stream[PromptCompletionChunk]: - ... + ) -> Stream[PromptCompletionChunk]: ... @overload def create( @@ -508,8 +507,7 @@ def create( top_p: Union[float, NotGiven] = NOT_GIVEN, extra_headers: Mapping[str, str] = {}, **kwargs, - ) -> PromptCompletion: - ... + ) -> PromptCompletion: ... @overload def create( @@ -525,8 +523,7 @@ def create( top_p: Union[float, NotGiven] = NOT_GIVEN, extra_headers: Mapping[str, str] = {}, **kwargs, - ) -> Union[PromptCompletion, Stream[PromptCompletionChunk]]: - ... + ) -> Union[PromptCompletion, Stream[PromptCompletionChunk]]: ... def create( self, @@ -584,8 +581,7 @@ async def create( top_p: Union[float, NotGiven] = NOT_GIVEN, extra_headers: Mapping[str, str] = {}, **kwargs, - ) -> AsyncStream[PromptCompletionChunk]: - ... + ) -> AsyncStream[PromptCompletionChunk]: ... @overload async def create( @@ -601,8 +597,7 @@ async def create( top_p: Union[float, NotGiven] = NOT_GIVEN, extra_headers: Mapping[str, str] = {}, **kwargs, - ) -> PromptCompletion: - ... + ) -> PromptCompletion: ... @overload async def create( @@ -618,8 +613,7 @@ async def create( top_p: Union[float, NotGiven] = NOT_GIVEN, extra_headers: Mapping[str, str] = {}, **kwargs, - ) -> Union[PromptCompletion, AsyncStream[PromptCompletionChunk]]: - ... + ) -> Union[PromptCompletion, AsyncStream[PromptCompletionChunk]]: ... async def create( self, diff --git a/portkey_ai/api_resources/apis/images.py b/portkey_ai/api_resources/apis/images.py index e2e5eddc..cc3e0738 100644 --- a/portkey_ai/api_resources/apis/images.py +++ b/portkey_ai/api_resources/apis/images.py @@ -29,7 +29,7 @@ def create_variation( response_format: Union[str, Omit] = omit, size: Union[str, Omit] = omit, user: Union[str, Omit] = omit, - **kwargs + **kwargs, ) -> ImagesResponse: response = self.openai_client.with_raw_response.images.create_variation( image=image, @@ -64,9 +64,8 @@ def edit( size: Union[Optional[str], Omit] = omit, stream: Union[Optional[Literal[False]], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Union[OpenAIImagesResponse, ImagesResponse]: - ... + **kwargs, + ) -> Union[OpenAIImagesResponse, ImagesResponse]: ... @overload def edit( @@ -87,9 +86,8 @@ def edit( response_format: Union[Optional[str], Omit] = omit, size: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Stream[ImageEditStreamEvent]: - ... + **kwargs, + ) -> Stream[ImageEditStreamEvent]: ... @overload def edit( @@ -110,9 +108,8 @@ def edit( response_format: Union[Optional[str], Omit] = omit, size: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Union[OpenAIImagesResponse, Stream[ImageEditStreamEvent], ImagesResponse]: - ... + **kwargs, + ) -> Union[OpenAIImagesResponse, Stream[ImageEditStreamEvent], ImagesResponse]: ... def edit( self, @@ -132,7 +129,7 @@ def edit( size: Union[Optional[str], Omit] = omit, stream: Union[Optional[Literal[False]], Literal[True], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs + **kwargs, ) -> Union[OpenAIImagesResponse, Stream[ImageEditStreamEvent], ImagesResponse]: extra_headers = kwargs.pop("extra_headers", None) extra_query = kwargs.pop("extra_query", None) @@ -205,9 +202,8 @@ def generate( stream: Union[Optional[Literal[False]], Omit] = omit, style: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Union[OpenAIImagesResponse, ImagesResponse]: - ... + **kwargs, + ) -> Union[OpenAIImagesResponse, ImagesResponse]: ... @overload def generate( @@ -227,9 +223,8 @@ def generate( size: Union[Optional[str], Omit] = omit, style: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Stream[ImageGenStreamEvent]: - ... + **kwargs, + ) -> Stream[ImageGenStreamEvent]: ... @overload def generate( @@ -249,9 +244,8 @@ def generate( size: Union[Optional[str], Omit] = omit, style: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Union[OpenAIImagesResponse, Stream[ImageGenStreamEvent], ImagesResponse]: - ... + **kwargs, + ) -> Union[OpenAIImagesResponse, Stream[ImageGenStreamEvent], ImagesResponse]: ... def generate( self, @@ -270,7 +264,7 @@ def generate( stream: Union[Optional[Union[Literal[False], Literal[True]]], Omit] = omit, style: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs + **kwargs, ) -> Union[OpenAIImagesResponse, Stream[ImageGenStreamEvent], ImagesResponse]: extra_headers = kwargs.pop("extra_headers", None) extra_query = kwargs.pop("extra_query", None) @@ -338,7 +332,7 @@ async def create_variation( response_format: Union[str, Omit] = omit, size: Union[str, Omit] = omit, user: Union[str, Omit] = omit, - **kwargs + **kwargs, ) -> ImagesResponse: response = await self.openai_client.with_raw_response.images.create_variation( image=image, @@ -372,9 +366,8 @@ async def edit( size: Union[Optional[str], Omit] = omit, stream: Union[Optional[Literal[False]], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Union[OpenAIImagesResponse, ImagesResponse]: - ... + **kwargs, + ) -> Union[OpenAIImagesResponse, ImagesResponse]: ... @overload async def edit( @@ -395,9 +388,8 @@ async def edit( response_format: Union[Optional[str], Omit] = omit, size: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> AsyncStream[ImageEditStreamEvent]: - ... + **kwargs, + ) -> AsyncStream[ImageEditStreamEvent]: ... @overload async def edit( @@ -418,9 +410,10 @@ async def edit( response_format: Union[Optional[str], Omit] = omit, size: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Union[OpenAIImagesResponse, AsyncStream[ImageEditStreamEvent], ImagesResponse]: - ... + **kwargs, + ) -> Union[ + OpenAIImagesResponse, AsyncStream[ImageEditStreamEvent], ImagesResponse + ]: ... async def edit( self, @@ -440,7 +433,7 @@ async def edit( size: Union[Optional[str], Omit] = omit, stream: Union[Optional[Literal[False]], Literal[True], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs + **kwargs, ) -> Union[OpenAIImagesResponse, AsyncStream[ImageEditStreamEvent], ImagesResponse]: extra_headers = kwargs.pop("extra_headers", None) extra_query = kwargs.pop("extra_query", None) @@ -513,9 +506,8 @@ async def generate( stream: Union[Optional[Literal[False]], Omit] = omit, style: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Union[OpenAIImagesResponse, ImagesResponse]: - ... + **kwargs, + ) -> Union[OpenAIImagesResponse, ImagesResponse]: ... @overload async def generate( @@ -535,9 +527,8 @@ async def generate( size: Union[Optional[str], Omit] = omit, style: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> AsyncStream[ImageGenStreamEvent]: - ... + **kwargs, + ) -> AsyncStream[ImageGenStreamEvent]: ... @overload async def generate( @@ -557,9 +548,10 @@ async def generate( size: Union[Optional[str], Omit] = omit, style: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs - ) -> Union[OpenAIImagesResponse, AsyncStream[ImageGenStreamEvent], ImagesResponse]: - ... + **kwargs, + ) -> Union[ + OpenAIImagesResponse, AsyncStream[ImageGenStreamEvent], ImagesResponse + ]: ... async def generate( self, @@ -578,7 +570,7 @@ async def generate( stream: Union[Optional[Union[Literal[False], Literal[True]]], Omit] = omit, style: Union[Optional[str], Omit] = omit, user: Union[str, Omit] = omit, - **kwargs + **kwargs, ) -> Union[OpenAIImagesResponse, AsyncStream[ImageGenStreamEvent], ImagesResponse]: extra_headers = kwargs.pop("extra_headers", None) extra_query = kwargs.pop("extra_query", None) diff --git a/portkey_ai/api_resources/apis/moderations.py b/portkey_ai/api_resources/apis/moderations.py index 74e3f11b..0079d35d 100644 --- a/portkey_ai/api_resources/apis/moderations.py +++ b/portkey_ai/api_resources/apis/moderations.py @@ -16,7 +16,7 @@ def create( *, input: Union[str, List[str], Iterable[Any]], model: Union[str, Omit] = omit, - **kwargs + **kwargs, ) -> ModerationCreateResponse: response = self.openai_client.with_raw_response.moderations.create( input=input, model=model, extra_body=kwargs @@ -37,7 +37,7 @@ async def create( *, input: Union[str, List[str], Iterable[Any]], model: Union[str, Omit] = omit, - **kwargs + **kwargs, ) -> ModerationCreateResponse: response = await self.openai_client.with_raw_response.moderations.create( input=input, model=model, extra_body=kwargs diff --git a/portkey_ai/api_resources/apis/post.py b/portkey_ai/api_resources/apis/post.py index c2033f88..208d44a6 100644 --- a/portkey_ai/api_resources/apis/post.py +++ b/portkey_ai/api_resources/apis/post.py @@ -18,8 +18,7 @@ def create( url: str, stream: Literal[True], **kwargs, - ) -> Stream[GenericResponse]: - ... + ) -> Stream[GenericResponse]: ... @overload def create( @@ -28,8 +27,7 @@ def create( url: str, stream: Literal[False] = False, **kwargs, - ) -> GenericResponse: - ... + ) -> GenericResponse: ... @overload def create( @@ -38,8 +36,7 @@ def create( url: str, stream: bool = False, **kwargs, - ) -> Union[GenericResponse, Stream[GenericResponse]]: - ... + ) -> Union[GenericResponse, Stream[GenericResponse]]: ... def create( self, @@ -73,8 +70,7 @@ async def create( url: str, stream: Literal[True], **kwargs, - ) -> AsyncStream[GenericResponse]: - ... + ) -> AsyncStream[GenericResponse]: ... @overload async def create( @@ -83,8 +79,7 @@ async def create( url: str, stream: Literal[False] = False, **kwargs, - ) -> GenericResponse: - ... + ) -> GenericResponse: ... @overload async def create( @@ -93,8 +88,7 @@ async def create( url: str, stream: bool = False, **kwargs, - ) -> Union[GenericResponse, AsyncStream[GenericResponse]]: - ... + ) -> Union[GenericResponse, AsyncStream[GenericResponse]]: ... async def create( self, diff --git a/portkey_ai/api_resources/apis/responses.py b/portkey_ai/api_resources/apis/responses.py index 89f698f8..8b3bf329 100644 --- a/portkey_ai/api_resources/apis/responses.py +++ b/portkey_ai/api_resources/apis/responses.py @@ -108,8 +108,7 @@ def create( truncation: Union[Optional[Literal["auto", "disabled"]], Omit] = omit, user: Union[str, Omit] = omit, **kwargs, - ) -> Response: - ... + ) -> Response: ... @overload def create( @@ -153,8 +152,7 @@ def create( truncation: Union[Optional[Literal["auto", "disabled"]], Omit] = omit, user: Union[str, Omit] = omit, **kwargs, - ) -> Stream[ResponseStreamEvent]: - ... + ) -> Stream[ResponseStreamEvent]: ... @overload def create( @@ -198,8 +196,7 @@ def create( truncation: Union[Optional[Literal["auto", "disabled"]], Omit] = omit, user: Union[str, Omit] = omit, **kwargs, - ) -> Union[Response, Stream[ResponseStreamEvent]]: - ... + ) -> Union[Response, Stream[ResponseStreamEvent]]: ... def create( self, @@ -294,8 +291,7 @@ def retrieve( starting_after: Union[int, Omit] = omit, stream: Union[Literal[False], Omit] = omit, **kwargs, - ) -> ResponseType: - ... + ) -> ResponseType: ... @overload def retrieve( @@ -307,8 +303,7 @@ def retrieve( include_obfuscation: Union[bool, Omit] = omit, starting_after: Union[int, Omit] = omit, **kwargs, - ) -> Stream[ResponseStreamEvent]: - ... + ) -> Stream[ResponseStreamEvent]: ... @overload def retrieve( @@ -320,8 +315,7 @@ def retrieve( include_obfuscation: Union[bool, Omit] = omit, starting_after: Union[int, Omit] = omit, **kwargs, - ) -> Union[ResponseType, Stream[ResponseStreamEvent]]: - ... + ) -> Union[ResponseType, Stream[ResponseStreamEvent]]: ... def retrieve( self, @@ -391,8 +385,7 @@ def stream( starting_after: Union[int, Omit] = omit, tools: Union[Iterable[ParseableToolParam], Omit] = omit, **kwargs, - ) -> ResponseStreamManager[TextFormatT]: - ... + ) -> ResponseStreamManager[TextFormatT]: ... @overload def stream( @@ -436,8 +429,7 @@ def stream( truncation: Union[Optional[Literal["auto", "disabled"]], Omit] = omit, user: Union[str, Omit] = omit, **kwargs, - ) -> ResponseStreamManager[TextFormatT]: - ... + ) -> ResponseStreamManager[TextFormatT]: ... def stream( self, @@ -903,8 +895,7 @@ async def create( truncation: Union[Optional[Literal["auto", "disabled"]], Omit] = omit, user: Union[str, Omit] = omit, **kwargs, - ) -> Response: - ... + ) -> Response: ... @overload async def create( @@ -948,8 +939,7 @@ async def create( truncation: Union[Optional[Literal["auto", "disabled"]], Omit] = omit, user: Union[str, Omit] = omit, **kwargs, - ) -> AsyncStream[ResponseStreamEvent]: - ... + ) -> AsyncStream[ResponseStreamEvent]: ... @overload async def create( @@ -993,8 +983,7 @@ async def create( truncation: Union[Optional[Literal["auto", "disabled"]], Omit] = omit, user: Union[str, Omit] = omit, **kwargs, - ) -> Union[Response, AsyncStream[ResponseStreamEvent]]: - ... + ) -> Union[Response, AsyncStream[ResponseStreamEvent]]: ... async def create( self, @@ -1089,8 +1078,7 @@ async def retrieve( starting_after: Union[int, Omit] = omit, stream: Union[Literal[False], Omit] = omit, **kwargs, - ) -> ResponseType: - ... + ) -> ResponseType: ... @overload async def retrieve( @@ -1102,8 +1090,7 @@ async def retrieve( include_obfuscation: Union[bool, Omit] = omit, starting_after: Union[int, Omit] = omit, **kwargs, - ) -> AsyncStream[ResponseStreamEvent]: - ... + ) -> AsyncStream[ResponseStreamEvent]: ... @overload async def retrieve( @@ -1115,8 +1102,7 @@ async def retrieve( include_obfuscation: Union[bool, Omit] = omit, starting_after: Union[int, Omit] = omit, **kwargs, - ) -> Union[ResponseType, AsyncStream[ResponseStreamEvent]]: - ... + ) -> Union[ResponseType, AsyncStream[ResponseStreamEvent]]: ... async def retrieve( self, @@ -1186,8 +1172,7 @@ def stream( starting_after: Union[int, Omit] = omit, tools: Union[Iterable[ParseableToolParam], Omit] = omit, **kwargs, - ) -> AsyncResponseStreamManager[TextFormatT]: - ... + ) -> AsyncResponseStreamManager[TextFormatT]: ... @overload def stream( @@ -1231,8 +1216,7 @@ def stream( truncation: Union[Optional[Literal["auto", "disabled"]], Omit] = omit, user: Union[str, Omit] = omit, **kwargs, - ) -> AsyncResponseStreamManager[TextFormatT]: - ... + ) -> AsyncResponseStreamManager[TextFormatT]: ... def stream( self, diff --git a/portkey_ai/api_resources/apis/threads.py b/portkey_ai/api_resources/apis/threads.py index 9d47a603..6d67798d 100644 --- a/portkey_ai/api_resources/apis/threads.py +++ b/portkey_ai/api_resources/apis/threads.py @@ -860,8 +860,10 @@ async def delete( async def stream_create_and_run( self, assistant_id, **kwargs ) -> Union[Run, AsyncIterator[AssistantStreamEvent]]: - async with self.openai_client.with_streaming_response.beta.threads.create_and_run( # noqa: E501 - assistant_id=assistant_id, stream=True, extra_body=kwargs + async with ( + self.openai_client.with_streaming_response.beta.threads.create_and_run( # noqa: E501 + assistant_id=assistant_id, stream=True, extra_body=kwargs + ) ) as streaming: async for line in streaming.iter_lines(): json_string = line.replace("data: ", "") @@ -967,12 +969,10 @@ async def create_and_run_stream( ] = omit, event_handler: Union[AsyncAssistantEventHandlerT, None] = None, **kwargs, - ) -> ( - Union[ - AsyncAssistantStreamManager[AsyncAssistantEventHandler], - AsyncAssistantStreamManager[AsyncAssistantEventHandlerT], - ] - ): + ) -> Union[ + AsyncAssistantStreamManager[AsyncAssistantEventHandler], + AsyncAssistantStreamManager[AsyncAssistantEventHandlerT], + ]: response = await self.openai_client.beta.threads.create_and_run_stream( assistant_id=assistant_id, instructions=instructions, @@ -1300,12 +1300,10 @@ async def create_and_stream( thread_id: str, event_handler: Union[AsyncAssistantEventHandlerT, None] = None, **kwargs, - ) -> ( - Union[ - AsyncAssistantStreamManager[AsyncAssistantEventHandler], - AsyncAssistantStreamManager[AsyncAssistantEventHandlerT], - ] - ): + ) -> Union[ + AsyncAssistantStreamManager[AsyncAssistantEventHandler], + AsyncAssistantStreamManager[AsyncAssistantEventHandlerT], + ]: response = await self.openai_client.beta.threads.runs.create_and_stream( assistant_id=assistant_id, additional_instructions=additional_instructions, @@ -1372,12 +1370,10 @@ async def stream( thread_id: str, event_handler: Union[AsyncAssistantEventHandlerT, None] = None, **kwargs, - ) -> ( - Union[ - AsyncAssistantStreamManager[AsyncAssistantEventHandler], - AsyncAssistantStreamManager[AsyncAssistantEventHandlerT], - ] - ): + ) -> Union[ + AsyncAssistantStreamManager[AsyncAssistantEventHandler], + AsyncAssistantStreamManager[AsyncAssistantEventHandlerT], + ]: response = await self.openai_client.beta.threads.runs.stream( assistant_id=assistant_id, include=include, diff --git a/portkey_ai/api_resources/apis/vector_stores.py b/portkey_ai/api_resources/apis/vector_stores.py index ed51717d..206e23ff 100644 --- a/portkey_ai/api_resources/apis/vector_stores.py +++ b/portkey_ai/api_resources/apis/vector_stores.py @@ -414,15 +414,17 @@ def list_files( order: Union[str, Omit] = omit, **kwargs, ) -> VectorStoreFileList: - response = self.openai_client.with_raw_response.vector_stores.file_batches.list_files( # noqa: E501 - batch_id=batch_id, - vector_store_id=vector_store_id, - after=after, - before=before, - filter=filter, - limit=limit, - order=order, - **kwargs, + response = ( + self.openai_client.with_raw_response.vector_stores.file_batches.list_files( # noqa: E501 + batch_id=batch_id, + vector_store_id=vector_store_id, + after=after, + before=before, + filter=filter, + limit=limit, + order=order, + **kwargs, + ) ) data = VectorStoreFileList(**json.loads(response.text)) data._headers = response.headers @@ -617,15 +619,19 @@ async def retrieve( **kwargs, ) -> VectorStoreFile: if kwargs: - response = await self.openai_client.with_raw_response.vector_stores.files.retrieve( # noqa: E501 - file_id=file_id, - vector_store_id=vector_store_id, - extra_body=kwargs, + response = ( + await self.openai_client.with_raw_response.vector_stores.files.retrieve( # noqa: E501 + file_id=file_id, + vector_store_id=vector_store_id, + extra_body=kwargs, + ) ) else: - response = await self.openai_client.with_raw_response.vector_stores.files.retrieve( # noqa: E501 - file_id=file_id, - vector_store_id=vector_store_id, + response = ( + await self.openai_client.with_raw_response.vector_stores.files.retrieve( # noqa: E501 + file_id=file_id, + vector_store_id=vector_store_id, + ) ) data = VectorStoreFile(**json.loads(response.text)) data._headers = response.headers diff --git a/portkey_ai/api_resources/base_client.py b/portkey_ai/api_resources/base_client.py index ee98482a..82458946 100644 --- a/portkey_ai/api_resources/base_client.py +++ b/portkey_ai/api_resources/base_client.py @@ -218,8 +218,7 @@ def _post( stream_cls: type[StreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> StreamT: - ... + ) -> StreamT: ... @overload def _post( @@ -233,8 +232,7 @@ def _post( stream_cls: type[StreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload def _post( @@ -248,8 +246,7 @@ def _post( stream_cls: type[StreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> Union[ResponseT, StreamT]: - ... + ) -> Union[ResponseT, StreamT]: ... def _post( self, @@ -303,8 +300,7 @@ def _put( stream_cls: type[StreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> StreamT: - ... + ) -> StreamT: ... @overload def _put( @@ -317,8 +313,7 @@ def _put( stream_cls: type[StreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload def _put( @@ -331,8 +326,7 @@ def _put( stream_cls: type[StreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> Union[ResponseT, StreamT]: - ... + ) -> Union[ResponseT, StreamT]: ... def _put( self, @@ -372,8 +366,7 @@ def _get( cast_to: Type[ResponseT], stream: Literal[True], stream_cls: type[StreamT], - ) -> StreamT: - ... + ) -> StreamT: ... @overload def _get( @@ -386,8 +379,7 @@ def _get( cast_to: Type[ResponseT], stream: Literal[False], stream_cls: type[StreamT], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload def _get( @@ -400,8 +392,7 @@ def _get( cast_to: Type[ResponseT], stream: bool, stream_cls: type[StreamT], - ) -> Union[ResponseT, StreamT]: - ... + ) -> Union[ResponseT, StreamT]: ... def _get( self, @@ -441,8 +432,7 @@ def _delete( cast_to: Type[ResponseT], stream: Literal[True], stream_cls: type[StreamT], - ) -> StreamT: - ... + ) -> StreamT: ... @overload def _delete( @@ -455,8 +445,7 @@ def _delete( cast_to: Type[ResponseT], stream: Literal[False], stream_cls: type[StreamT], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload def _delete( @@ -469,8 +458,7 @@ def _delete( cast_to: Type[ResponseT], stream: bool, stream_cls: type[StreamT], - ) -> Union[ResponseT, StreamT]: - ... + ) -> Union[ResponseT, StreamT]: ... def _delete( self, @@ -630,8 +618,7 @@ def _request( stream: Literal[False], cast_to: Type[ResponseT], stream_cls: Type[StreamT], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload def _request( @@ -642,8 +629,7 @@ def _request( stream: Literal[True], cast_to: Type[ResponseT], stream_cls: Type[StreamT], - ) -> StreamT: - ... + ) -> StreamT: ... @overload def _request( @@ -654,8 +640,7 @@ def _request( stream: bool, cast_to: Type[ResponseT], stream_cls: Type[StreamT], - ) -> Union[ResponseT, StreamT]: - ... + ) -> Union[ResponseT, StreamT]: ... def _request( self, @@ -933,8 +918,7 @@ async def _post( stream_cls: type[AsyncStreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload async def _post( @@ -948,8 +932,7 @@ async def _post( stream_cls: type[AsyncStreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> AsyncStreamT: - ... + ) -> AsyncStreamT: ... @overload async def _post( @@ -963,8 +946,7 @@ async def _post( stream_cls: type[AsyncStreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> Union[ResponseT, AsyncStreamT]: - ... + ) -> Union[ResponseT, AsyncStreamT]: ... async def _post( self, @@ -1018,8 +1000,7 @@ async def _put( stream_cls: type[AsyncStreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload async def _put( @@ -1032,8 +1013,7 @@ async def _put( stream_cls: type[AsyncStreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> AsyncStreamT: - ... + ) -> AsyncStreamT: ... @overload async def _put( @@ -1046,8 +1026,7 @@ async def _put( stream_cls: type[AsyncStreamT], params: Mapping[str, str], headers: Mapping[str, str], - ) -> Union[ResponseT, AsyncStreamT]: - ... + ) -> Union[ResponseT, AsyncStreamT]: ... async def _put( self, @@ -1087,8 +1066,7 @@ async def _get( cast_to: Type[ResponseT], stream: Literal[True], stream_cls: type[AsyncStreamT], - ) -> AsyncStreamT: - ... + ) -> AsyncStreamT: ... @overload async def _get( @@ -1101,8 +1079,7 @@ async def _get( cast_to: Type[ResponseT], stream: Literal[False], stream_cls: type[AsyncStreamT], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload async def _get( @@ -1115,8 +1092,7 @@ async def _get( cast_to: Type[ResponseT], stream: bool, stream_cls: type[AsyncStreamT], - ) -> Union[ResponseT, AsyncStreamT]: - ... + ) -> Union[ResponseT, AsyncStreamT]: ... async def _get( self, @@ -1156,8 +1132,7 @@ async def _delete( cast_to: Type[ResponseT], stream: Literal[True], stream_cls: type[AsyncStreamT], - ) -> AsyncStreamT: - ... + ) -> AsyncStreamT: ... @overload async def _delete( @@ -1170,8 +1145,7 @@ async def _delete( cast_to: Type[ResponseT], stream: Literal[False], stream_cls: type[AsyncStreamT], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload async def _delete( @@ -1184,8 +1158,7 @@ async def _delete( cast_to: Type[ResponseT], stream: bool, stream_cls: type[AsyncStreamT], - ) -> Union[ResponseT, AsyncStreamT]: - ... + ) -> Union[ResponseT, AsyncStreamT]: ... async def _delete( self, @@ -1344,8 +1317,7 @@ async def _request( stream: Literal[False], cast_to: Type[ResponseT], stream_cls: Type[AsyncStreamT], - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload async def _request( @@ -1356,8 +1328,7 @@ async def _request( stream: Literal[True], cast_to: Type[ResponseT], stream_cls: Type[AsyncStreamT], - ) -> AsyncStreamT: - ... + ) -> AsyncStreamT: ... @overload async def _request( @@ -1368,8 +1339,7 @@ async def _request( stream: bool, cast_to: Type[ResponseT], stream_cls: Type[AsyncStreamT], - ) -> Union[ResponseT, AsyncStreamT]: - ... + ) -> Union[ResponseT, AsyncStreamT]: ... async def _request( self, diff --git a/portkey_ai/api_resources/streaming.py b/portkey_ai/api_resources/streaming.py index c94d9dd0..def221b5 100644 --- a/portkey_ai/api_resources/streaming.py +++ b/portkey_ai/api_resources/streaming.py @@ -165,9 +165,11 @@ def __stream__(self) -> Iterator[ResponseT]: if sse.data.startswith("[DONE]"): break if sse.event is None: - yield cast(ResponseT, self._cast_to(**sse.json())) if not isinstance( - self._cast_to, httpx.Response - ) else cast(ResponseT, sse) + yield ( + cast(ResponseT, self._cast_to(**sse.json())) + if not isinstance(self._cast_to, httpx.Response) + else cast(ResponseT, sse) + ) if sse.event == "ping": continue @@ -232,9 +234,11 @@ async def __stream__(self) -> AsyncIterator[ResponseT]: if sse.data.startswith("[DONE]"): break if sse.event is None: - yield cast(ResponseT, self._cast_to(**sse.json())) if not isinstance( - self._cast_to, httpx.Response - ) else cast(ResponseT, sse) + yield ( + cast(ResponseT, self._cast_to(**sse.json())) + if not isinstance(self._cast_to, httpx.Response) + else cast(ResponseT, sse) + ) if sse.event == "ping": continue diff --git a/portkey_ai/api_resources/utils.py b/portkey_ai/api_resources/utils.py index bd124b8a..b7381bee 100644 --- a/portkey_ai/api_resources/utils.py +++ b/portkey_ai/api_resources/utils.py @@ -230,12 +230,11 @@ class ModelParams(BaseModel): tools: Optional[List[Tool]] = None -class OverrideParams(ModelParams, ConversationInput): - ... +class OverrideParams(ModelParams, ConversationInput): ... def remove_empty_values( - data: Union[Dict[str, Any], Mapping[str, Any]] + data: Union[Dict[str, Any], Mapping[str, Any]], ) -> Dict[str, Any]: if isinstance(data, dict): cleaned_dict = {} @@ -329,16 +328,14 @@ class RequestConfig(BaseModel): options: List[ProviderOptions] -class Body(LLMOptions): - ... +class Body(LLMOptions): ... class ConfigSlug(BaseModel): config: str -class Params(Constructs, ConversationInput, ModelParams, extra="forbid"): - ... +class Params(Constructs, ConversationInput, ModelParams, extra="forbid"): ... class RequestData(BaseModel): diff --git a/portkey_ai/langchain/portkey_langchain_callback_handler.py b/portkey_ai/langchain/portkey_langchain_callback_handler.py index d3470788..65440e24 100644 --- a/portkey_ai/langchain/portkey_langchain_callback_handler.py +++ b/portkey_ai/langchain/portkey_langchain_callback_handler.py @@ -97,9 +97,9 @@ def on_llm_end( response_payload = self.on_llm_end_transformer(response, kwargs=kwargs) self.event_map["llm_start_" + str(run_id)]["response"] = response_payload - self.event_map["llm_start_" + str(run_id)]["response"][ - "response_time" - ] = total_time + self.event_map["llm_start_" + str(run_id)]["response"]["response_time"] = ( + total_time + ) self.event_array.append(self.event_map["llm_start_" + str(run_id)]) @@ -166,9 +166,9 @@ def on_chain_end( response_payload = self.on_chain_end_transformer(outputs) self.event_map["chain_start_" + str(run_id)]["response"] = response_payload - self.event_map["chain_start_" + str(run_id)]["response"][ - "response_time" - ] = total_time + self.event_map["chain_start_" + str(run_id)]["response"]["response_time"] = ( + total_time + ) self.event_array.append(self.event_map["chain_start_" + str(run_id)]) @@ -225,9 +225,9 @@ def on_tool_end( response_payload = self.on_tool_end_transformer(output) self.event_map["tool_start_" + str(run_id)]["response"] = response_payload - self.event_map["tool_start_" + str(run_id)]["response"][ - "response_time" - ] = total_time + self.event_map["tool_start_" + str(run_id)]["response"]["response_time"] = ( + total_time + ) self.event_array.append(self.event_map["tool_start_" + str(run_id)]) pass @@ -396,16 +396,28 @@ def on_llm_end_transformer(self, response, kwargs): "role": "assistant", "content": response.generations[0][0].text, }, - "logprobs": response.generations[0][0].generation_info.get("logprobs", ""), # type: ignore[union-attr] # noqa: E501 - "finish_reason": response.generations[0][0].generation_info.get("finish_reason", ""), # type: ignore[union-attr] # noqa: E501 + "logprobs": response.generations[0][0].generation_info.get( + "logprobs", "" + ), # type: ignore[union-attr] # noqa: E501 + "finish_reason": response.generations[0][0].generation_info.get( + "finish_reason", "" + ), # type: ignore[union-attr] # noqa: E501 } ] } response_obj["body"].update({"usage": usage}) response_obj["body"].update({"id": str(kwargs.get("run_id", ""))}) response_obj["body"].update({"created": int(time.time())}) - response_obj["body"].update({"model": (response.llm_output or {}).get("model_name", "")}) # type: ignore[union-attr] # noqa: E501 - response_obj["body"].update({"system_fingerprint": (response.llm_output or {}).get("system_fingerprint", "")}) # type: ignore[union-attr] # noqa: E501 + response_obj["body"].update( + {"model": (response.llm_output or {}).get("model_name", "")} + ) # type: ignore[union-attr] # noqa: E501 + response_obj["body"].update( + { + "system_fingerprint": (response.llm_output or {}).get( + "system_fingerprint", "" + ) + } + ) # type: ignore[union-attr] # noqa: E501 response_obj["headers"] = {} return response_obj except Exception: diff --git a/portkey_ai/llms/llama_index/utils.py b/portkey_ai/llms/llama_index/utils.py index b893563a..91de1962 100644 --- a/portkey_ai/llms/llama_index/utils.py +++ b/portkey_ai/llms/llama_index/utils.py @@ -4,6 +4,7 @@ This file module contains a collection of utility functions designed to enhance the functionality and usability of the Portkey class """ + from typing import TYPE_CHECKING @@ -114,7 +115,7 @@ def modelname_to_contextsize(modelname: str) -> int: if modelname in DISCONTINUED_MODELS: raise ValueError( - f"Model {modelname} has been discontinued. " "Please choose another model." + f"Model {modelname} has been discontinued. Please choose another model." ) context_size = ALL_AVAILABLE_MODELS.get(modelname, None) diff --git a/pyproject.toml b/pyproject.toml index 980f01ee..f7fa5eb7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,10 +15,18 @@ disable_error_code = ['import-untyped', 'import-not-found'] module = 'portkey_ai._vendor.*' ignore_errors = true -[tool.black] -force-exclude = '''(portkey_ai/_vendor)/''' - [tool.ruff] -exclude = ["portkey_ai/_vendor", "tests"] -ignore = ["E501"] +# `*.md` is excluded because ruff formats Python code blocks inside Markdown. +# README/CLAUDE.md snippets are illustrative -- abbreviated bodies and blank +# lines used for grouping are intentional, and reformatting them is churn. +exclude = ["portkey_ai/_vendor", "tests", "*.md"] line-length = 88 +target-version = "py38" + +[tool.ruff.lint] +# Pin the rule set explicitly. Under ruff 0.0.292 these were the effective +# defaults, but leaving `select` unset means a future ruff upgrade silently +# enables new rule families -- upgrading with it unset surfaced 7176 findings. +# Widen this deliberately, in its own PR. +select = ["E4", "E7", "E9", "F"] +ignore = ["E501"] diff --git a/setup.cfg b/setup.cfg index e72d5876..abed0269 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,10 +50,10 @@ dev = mypy==1.20.2; python_version >= "3.10" mypy==1.19.1; python_version == "3.9" mypy==1.14.1; python_version < "3.9" - black==23.7.0 pytest==7.4.2 python-dotenv==1.0.0 - ruff==0.0.292 + # ruff replaces black as the formatter (`ruff format`) as well as the linter. + ruff==0.16.2 pytest-asyncio==0.23.5 pre-commit==4.3.0; python_version >= "3.9" langchain_callback = From c9e9e696b931eab98069477ebf886846c12a39a8 Mon Sep 17 00:00:00 2001 From: Chandra Kiran G Date: Thu, 13 Aug 2026 12:38:18 +0530 Subject: [PATCH 6/6] chore: Fix formatting --- examples/adk_streaming_thinking_usage.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/adk_streaming_thinking_usage.py b/examples/adk_streaming_thinking_usage.py index 4cbc4c21..a9d03bdf 100644 --- a/examples/adk_streaming_thinking_usage.py +++ b/examples/adk_streaming_thinking_usage.py @@ -102,9 +102,9 @@ def _build_request( thinking_budget=thinking_budget, ) if enable_tool_call: - config_kwargs[ - "system_instruction" - ] = "When the user asks about weather, call the provided tool exactly once." + config_kwargs["system_instruction"] = ( + "When the user asks about weather, call the provided tool exactly once." + ) config_kwargs["tools"] = [_build_weather_tool()] if config_kwargs: kwargs["config"] = genai_types.GenerateContentConfig(**config_kwargs)