From 3b8e137873f4704152cfbed2af8335dc89bf162e Mon Sep 17 00:00:00 2001 From: Jinhao Xu Date: Wed, 2 Sep 2026 18:08:35 +0800 Subject: [PATCH] fix: restore PyPI name x402-openai and import x402_openai Keep the 1.0 API. Drop the qntx.openai namespace; no shim. --- .pre-commit-config.yaml | 2 +- Justfile | 2 +- Makefile | 2 +- README.md | 28 ++--- examples/chat_evm.py | 2 +- examples/chat_evm_policy.py | 2 +- examples/chat_multichain_policy.py | 2 +- examples/chat_policy.py | 2 +- examples/chat_svm.py | 2 +- examples/chat_tvm.py | 2 +- examples/chat_upto.py | 2 +- examples/models.py | 2 +- examples/streaming_evm.py | 2 +- examples/streaming_evm_policy.py | 2 +- examples/streaming_svm.py | 2 +- pyproject.toml | 14 +-- src/{qntx/openai => x402_openai}/__init__.py | 10 +- .../_chains/__init__.py | 4 +- .../openai => x402_openai}/_chains/_evm.py | 4 +- .../_chains/_register.py | 12 +- .../openai => x402_openai}/_chains/_svm.py | 4 +- .../openai => x402_openai}/_chains/_tvm.py | 4 +- .../openai => x402_openai}/_chains/_types.py | 0 src/{qntx/openai => x402_openai}/_client.py | 10 +- src/{qntx/openai => x402_openai}/_payments.py | 4 +- src/{qntx/openai => x402_openai}/_policies.py | 2 +- .../openai => x402_openai}/_transport.py | 2 +- src/{qntx/openai => x402_openai}/py.typed | 0 tests/test_chains_evm.py | 8 +- tests/test_chains_svm.py | 10 +- tests/test_chains_tvm.py | 10 +- tests/test_client.py | 22 ++-- tests/test_missing_extra.py | 14 +-- tests/test_payments.py | 28 ++--- tests/test_policies.py | 2 +- tests/test_transport.py | 2 +- uv.lock | 116 +++++++++--------- 37 files changed, 167 insertions(+), 171 deletions(-) rename src/{qntx/openai => x402_openai}/__init__.py (72%) rename src/{qntx/openai => x402_openai}/_chains/__init__.py (58%) rename src/{qntx/openai => x402_openai}/_chains/_evm.py (92%) rename src/{qntx/openai => x402_openai}/_chains/_register.py (84%) rename src/{qntx/openai => x402_openai}/_chains/_svm.py (89%) rename src/{qntx/openai => x402_openai}/_chains/_tvm.py (93%) rename src/{qntx/openai => x402_openai}/_chains/_types.py (100%) rename src/{qntx/openai => x402_openai}/_client.py (98%) rename src/{qntx/openai => x402_openai}/_payments.py (96%) rename src/{qntx/openai => x402_openai}/_policies.py (95%) rename src/{qntx/openai => x402_openai}/_transport.py (99%) rename src/{qntx/openai => x402_openai}/py.typed (100%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 724a189..9f5b962 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: additional_dependencies: ["openai>=3.7.0", "httpx2>=2.12.0", "x402>=2.21.0"] args: [--strict, --config-file=pyproject.toml] pass_filenames: false - entry: mypy src/qntx/openai + entry: mypy src/x402_openai ci: autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks diff --git a/Justfile b/Justfile index 2886d37..5536864 100644 --- a/Justfile +++ b/Justfile @@ -21,7 +21,7 @@ format: # Run the mypy type checker. typecheck: - uv run mypy src/qntx/openai + uv run mypy src/x402_openai # Run pytest. test: diff --git a/Makefile b/Makefile index 0efface..e58a7a8 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ format: ## Run ruff formatter (auto-fix) uv run ruff format . typecheck: ## Run mypy type checker - uv run mypy src/qntx/openai + uv run mypy src/x402_openai test: ## Run pytest uv run pytest diff --git a/README.md b/README.md index c59ff08..ea05437 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@
-# qntx-openai +# x402-openai **Drop-in OpenAI Python client with transparent [x402](https://www.x402.org/) payment support.** -[![PyPI](https://img.shields.io/pypi/v/qntx-openai)](https://pypi.org/project/qntx-openai/) +[![PyPI](https://img.shields.io/pypi/v/x402-openai)](https://pypi.org/project/x402-openai/) [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue)](https://python.org) [![CI](https://github.com/qntx/openai-python/actions/workflows/python.yml/badge.svg)](https://github.com/qntx/openai-python/actions) [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE) @@ -23,18 +23,16 @@ Supplying `evm` registers both **`exact` and `upto`**. `svm` and `tvm` register ## Installation ```bash -pip install 'qntx-openai[evm]' # EVM (Ethereum / Base / …) -pip install 'qntx-openai[svm]' # Solana -pip install 'qntx-openai[tvm]' # TVM (TON) -pip install 'qntx-openai[all]' # all chains +pip install 'x402-openai[evm]' # EVM (Ethereum / Base / …) +pip install 'x402-openai[svm]' # Solana +pip install 'x402-openai[tvm]' # TVM (TON) +pip install 'x402-openai[all]' # all chains ``` -The PyPI name `x402-openai` is abandoned. Install `qntx-openai`. - ## Quick Start ```python -from qntx.openai import X402OpenAI +from x402_openai import X402OpenAI client = X402OpenAI(evm="0x…") @@ -52,7 +50,7 @@ Pass `svm="base58…"` instead of `evm` to pay on Solana — the rest of the API ### Streaming ```python -from qntx.openai import AsyncX402OpenAI +from x402_openai import AsyncX402OpenAI client = AsyncX402OpenAI(evm="0x…") @@ -124,7 +122,7 @@ client = X402OpenAI( - **SVM `exact`:** the 402 must include `extra.feePayer`. There is no SVM `upto` scheme in Python `x402`. ```python -from qntx.openai import X402OpenAI, prefer_scheme +from x402_openai import X402OpenAI, prefer_scheme client = X402OpenAI( evm="0x…", @@ -139,7 +137,7 @@ client = X402OpenAI( Use policies to prefer a chain or scheme when multiple options remain after spend controls. Policies do not cap spend. ```python -from qntx.openai import X402OpenAI, prefer_network, prefer_scheme +from x402_openai import X402OpenAI, prefer_network, prefer_scheme client = X402OpenAI( evm="0x…", @@ -194,9 +192,9 @@ All standard OpenAI options (`base_url`, `timeout`, `max_retries`, …) are forw | Option | Chain | Install extra | | :----- | :---- | :------------ | -| `evm` | EVM | `qntx-openai[evm]` | -| `svm` | Solana | `qntx-openai[svm]` | -| `tvm` | TVM | `qntx-openai[tvm]` | +| `evm` | EVM | `x402-openai[evm]` | +| `svm` | Solana | `x402-openai[svm]` | +| `tvm` | TVM | `x402-openai[tvm]` | ## Examples diff --git a/examples/chat_evm.py b/examples/chat_evm.py index 92fe01a..cdd155b 100644 --- a/examples/chat_evm.py +++ b/examples/chat_evm.py @@ -5,7 +5,7 @@ import os -from qntx.openai import X402OpenAI +from x402_openai import X402OpenAI client = X402OpenAI(evm=os.environ["EVM_PRIVATE_KEY"]) diff --git a/examples/chat_evm_policy.py b/examples/chat_evm_policy.py index a54855d..b4c457e 100644 --- a/examples/chat_evm_policy.py +++ b/examples/chat_evm_policy.py @@ -7,7 +7,7 @@ import os -from qntx.openai import X402OpenAI, prefer_network, prefer_scheme +from x402_openai import X402OpenAI, prefer_network, prefer_scheme client = X402OpenAI( evm=os.environ["EVM_PRIVATE_KEY"], diff --git a/examples/chat_multichain_policy.py b/examples/chat_multichain_policy.py index c37f894..8e21708 100644 --- a/examples/chat_multichain_policy.py +++ b/examples/chat_multichain_policy.py @@ -11,7 +11,7 @@ import os -from qntx.openai import X402OpenAI, prefer_network, prefer_scheme +from x402_openai import X402OpenAI, prefer_network, prefer_scheme client = X402OpenAI( evm=os.environ["EVM_PRIVATE_KEY"], diff --git a/examples/chat_policy.py b/examples/chat_policy.py index 45e7c60..4aab4a3 100644 --- a/examples/chat_policy.py +++ b/examples/chat_policy.py @@ -7,7 +7,7 @@ import os -from qntx.openai import X402OpenAI, prefer_network, prefer_scheme +from x402_openai import X402OpenAI, prefer_network, prefer_scheme client = X402OpenAI( evm=os.environ["EVM_PRIVATE_KEY"], diff --git a/examples/chat_svm.py b/examples/chat_svm.py index 5ac2af9..e539c68 100644 --- a/examples/chat_svm.py +++ b/examples/chat_svm.py @@ -5,7 +5,7 @@ import os -from qntx.openai import X402OpenAI +from x402_openai import X402OpenAI client = X402OpenAI(svm=os.environ["SOLANA_PRIVATE_KEY"]) diff --git a/examples/chat_tvm.py b/examples/chat_tvm.py index d24f585..e7581b9 100644 --- a/examples/chat_tvm.py +++ b/examples/chat_tvm.py @@ -8,7 +8,7 @@ import os -from qntx.openai import X402OpenAI +from x402_openai import X402OpenAI client = X402OpenAI(tvm=os.environ["TVM_PRIVATE_KEY"]) try: diff --git a/examples/chat_upto.py b/examples/chat_upto.py index 463433e..318219b 100644 --- a/examples/chat_upto.py +++ b/examples/chat_upto.py @@ -8,7 +8,7 @@ import os -from qntx.openai import X402OpenAI, prefer_scheme +from x402_openai import X402OpenAI, prefer_scheme client = X402OpenAI( evm=os.environ["EVM_PRIVATE_KEY"], diff --git a/examples/models.py b/examples/models.py index cdb7a26..cf292ec 100644 --- a/examples/models.py +++ b/examples/models.py @@ -5,7 +5,7 @@ import os -from qntx.openai import X402OpenAI +from x402_openai import X402OpenAI client = X402OpenAI(evm=os.environ["EVM_PRIVATE_KEY"]) diff --git a/examples/streaming_evm.py b/examples/streaming_evm.py index 77a95e8..f77154d 100644 --- a/examples/streaming_evm.py +++ b/examples/streaming_evm.py @@ -6,7 +6,7 @@ import asyncio import os -from qntx.openai import AsyncX402OpenAI +from x402_openai import AsyncX402OpenAI async def main() -> None: diff --git a/examples/streaming_evm_policy.py b/examples/streaming_evm_policy.py index c85219f..e0a185b 100644 --- a/examples/streaming_evm_policy.py +++ b/examples/streaming_evm_policy.py @@ -8,7 +8,7 @@ import asyncio import os -from qntx.openai import AsyncX402OpenAI, prefer_network, prefer_scheme +from x402_openai import AsyncX402OpenAI, prefer_network, prefer_scheme async def main() -> None: diff --git a/examples/streaming_svm.py b/examples/streaming_svm.py index 78108c5..5b49629 100644 --- a/examples/streaming_svm.py +++ b/examples/streaming_svm.py @@ -6,7 +6,7 @@ import asyncio import os -from qntx.openai import AsyncX402OpenAI +from x402_openai import AsyncX402OpenAI async def main() -> None: diff --git a/pyproject.toml b/pyproject.toml index d03af64..f4b7ce4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["hatchling"] build-backend = "hatchling.build" [project] -name = "qntx-openai" +name = "x402-openai" version = "1.0.0" description = "Drop-in OpenAI Python client with transparent x402 payment support." readme = "README.md" @@ -43,9 +43,9 @@ tvm = [ "x402[tvm]>=2.21.0", ] all = [ - "qntx-openai[evm]", - "qntx-openai[svm]", - "qntx-openai[tvm]", + "x402-openai[evm]", + "x402-openai[svm]", + "x402-openai[tvm]", ] dev = [ "pytest>=8.0", @@ -62,7 +62,7 @@ Repository = "https://github.com/qntx/openai-python" Issues = "https://github.com/qntx/openai-python/issues" [tool.hatch.build.targets.wheel] -packages = ["src/qntx"] +packages = ["src/x402_openai"] [tool.ruff] target-version = "py312" @@ -87,15 +87,13 @@ ignore = [ ] [tool.ruff.lint.isort] -known-first-party = ["qntx"] +known-first-party = ["x402_openai"] [tool.mypy] python_version = "3.12" strict = true warn_return_any = true warn_unused_configs = true -namespace_packages = true -explicit_package_bases = true mypy_path = "src" [[tool.mypy.overrides]] diff --git a/src/qntx/openai/__init__.py b/src/x402_openai/__init__.py similarity index 72% rename from src/qntx/openai/__init__.py rename to src/x402_openai/__init__.py index ec88936..5ba09de 100644 --- a/src/qntx/openai/__init__.py +++ b/src/x402_openai/__init__.py @@ -1,8 +1,8 @@ -"""qntx-openai — Drop-in OpenAI client with transparent x402 payment. +"""x402-openai — Drop-in OpenAI client with transparent x402 payment. Quick start:: - from qntx.openai import prefer_scheme, X402OpenAI + from x402_openai import prefer_scheme, X402OpenAI client = X402OpenAI(evm="0x…") @@ -24,9 +24,9 @@ from x402 import SpendControls, x402Client, x402ClientSync -from qntx.openai._chains._types import EvmConfig, SvmConfig, TvmConfig -from qntx.openai._client import AsyncX402OpenAI, X402OpenAI -from qntx.openai._policies import prefer_network, prefer_scheme +from x402_openai._chains._types import EvmConfig, SvmConfig, TvmConfig +from x402_openai._client import AsyncX402OpenAI, X402OpenAI +from x402_openai._policies import prefer_network, prefer_scheme __all__ = [ "AsyncX402OpenAI", diff --git a/src/qntx/openai/_chains/__init__.py b/src/x402_openai/_chains/__init__.py similarity index 58% rename from src/qntx/openai/_chains/__init__.py rename to src/x402_openai/_chains/__init__.py index 5f01e95..0939e20 100644 --- a/src/qntx/openai/_chains/__init__.py +++ b/src/x402_openai/_chains/__init__.py @@ -2,7 +2,7 @@ from __future__ import annotations -from qntx.openai._chains._register import ChainHandles, register_chains -from qntx.openai._chains._types import EvmConfig, SvmConfig, TvmConfig +from x402_openai._chains._register import ChainHandles, register_chains +from x402_openai._chains._types import EvmConfig, SvmConfig, TvmConfig __all__ = ["ChainHandles", "EvmConfig", "SvmConfig", "TvmConfig", "register_chains"] diff --git a/src/qntx/openai/_chains/_evm.py b/src/x402_openai/_chains/_evm.py similarity index 92% rename from src/qntx/openai/_chains/_evm.py rename to src/x402_openai/_chains/_evm.py index 0e59376..131a946 100644 --- a/src/qntx/openai/_chains/_evm.py +++ b/src/x402_openai/_chains/_evm.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: from x402 import x402Client, x402ClientSync - from qntx.openai._chains._types import EvmConfig + from x402_openai._chains._types import EvmConfig def register_evm(client: x402Client | x402ClientSync, config: EvmConfig) -> None: @@ -17,7 +17,7 @@ def register_evm(client: x402Client | x402ClientSync, config: EvmConfig) -> None from x402.mechanisms.evm.upto import UptoEvmScheme except ImportError as e: raise ImportError( - "EVM key provided but x402[evm] is not installed. pip install 'qntx-openai[evm]'" + "EVM key provided but x402[evm] is not installed. pip install 'x402-openai[evm]'" ) from e account = Account.from_key(config.private_key) diff --git a/src/qntx/openai/_chains/_register.py b/src/x402_openai/_chains/_register.py similarity index 84% rename from src/qntx/openai/_chains/_register.py rename to src/x402_openai/_chains/_register.py index a360958..2f06c2a 100644 --- a/src/qntx/openai/_chains/_register.py +++ b/src/x402_openai/_chains/_register.py @@ -4,16 +4,16 @@ from typing import TYPE_CHECKING -from qntx.openai._chains._evm import register_evm -from qntx.openai._chains._svm import register_svm -from qntx.openai._chains._tvm import register_tvm -from qntx.openai._chains._types import EvmConfig, SvmConfig, TvmConfig +from x402_openai._chains._evm import register_evm +from x402_openai._chains._svm import register_svm +from x402_openai._chains._tvm import register_tvm +from x402_openai._chains._types import EvmConfig, SvmConfig, TvmConfig if TYPE_CHECKING: from x402 import x402Client, x402ClientSync - from qntx.openai._chains._tvm import _TvmScheme - from qntx.openai._payments import PaymentSourceOptions + from x402_openai._chains._tvm import _TvmScheme + from x402_openai._payments import PaymentSourceOptions class ChainHandles: diff --git a/src/qntx/openai/_chains/_svm.py b/src/x402_openai/_chains/_svm.py similarity index 89% rename from src/qntx/openai/_chains/_svm.py rename to src/x402_openai/_chains/_svm.py index c0b4756..013bdcc 100644 --- a/src/qntx/openai/_chains/_svm.py +++ b/src/x402_openai/_chains/_svm.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: from x402 import x402Client, x402ClientSync - from qntx.openai._chains._types import SvmConfig + from x402_openai._chains._types import SvmConfig def register_svm(client: x402Client | x402ClientSync, config: SvmConfig) -> None: @@ -16,7 +16,7 @@ def register_svm(client: x402Client | x402ClientSync, config: SvmConfig) -> None from x402.mechanisms.svm.exact import ExactSvmScheme except ImportError as e: raise ImportError( - "SVM key provided but x402[svm] is not installed. pip install 'qntx-openai[svm]'" + "SVM key provided but x402[svm] is not installed. pip install 'x402-openai[svm]'" ) from e signer = KeypairSigner.from_base58(config.private_key) diff --git a/src/qntx/openai/_chains/_tvm.py b/src/x402_openai/_chains/_tvm.py similarity index 93% rename from src/qntx/openai/_chains/_tvm.py rename to src/x402_openai/_chains/_tvm.py index 01d9e91..7de0bb9 100644 --- a/src/qntx/openai/_chains/_tvm.py +++ b/src/x402_openai/_chains/_tvm.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: from x402 import x402Client, x402ClientSync - from qntx.openai._chains._types import TvmConfig + from x402_openai._chains._types import TvmConfig class _TvmScheme(Protocol): @@ -24,7 +24,7 @@ def register_tvm(client: x402Client | x402ClientSync, config: TvmConfig) -> _Tvm from x402.mechanisms.tvm.exact import ExactTvmScheme except ImportError as e: raise ImportError( - "TVM key provided but x402[tvm] is not installed. pip install 'qntx-openai[tvm]'" + "TVM key provided but x402[tvm] is not installed. pip install 'x402-openai[tvm]'" ) from e network = config.network or TVM_MAINNET diff --git a/src/qntx/openai/_chains/_types.py b/src/x402_openai/_chains/_types.py similarity index 100% rename from src/qntx/openai/_chains/_types.py rename to src/x402_openai/_chains/_types.py diff --git a/src/qntx/openai/_client.py b/src/x402_openai/_client.py similarity index 98% rename from src/qntx/openai/_client.py rename to src/x402_openai/_client.py index 9755605..e37189a 100644 --- a/src/qntx/openai/_client.py +++ b/src/x402_openai/_client.py @@ -7,22 +7,22 @@ from typing import TYPE_CHECKING, Any, Literal, Self import httpx2 -from httpx2._utils import get_environment_proxies - import openai +from httpx2._utils import get_environment_proxies from openai import DefaultAsyncHttpx2Client, DefaultHttpx2Client -from qntx.openai._payments import ( + +from x402_openai._payments import ( BuiltClient, PaymentSourceOptions, assert_payment_options, build_x402_client, ) -from qntx.openai._transport import X402Httpx2AsyncTransport, X402Httpx2SyncTransport +from x402_openai._transport import X402Httpx2AsyncTransport, X402Httpx2SyncTransport if TYPE_CHECKING: from x402 import SpendControls, x402Client, x402ClientSync - from qntx.openai._chains._types import EvmConfig, SvmConfig, TvmConfig + from x402_openai._chains._types import EvmConfig, SvmConfig, TvmConfig DEFAULT_BASE_URL = "https://llm.qntx.org/v1" _REMOVED = ("wallet", "wallets", "mnemonic", "max_amount", "http_client") diff --git a/src/qntx/openai/_payments.py b/src/x402_openai/_payments.py similarity index 96% rename from src/qntx/openai/_payments.py rename to src/x402_openai/_payments.py index 9f77575..ff17131 100644 --- a/src/qntx/openai/_payments.py +++ b/src/x402_openai/_payments.py @@ -9,10 +9,10 @@ from x402 import SpendControls, x402Client, x402ClientSync from x402.http import x402HTTPClient, x402HTTPClientSync -from qntx.openai._chains._register import register_chains +from x402_openai._chains._register import register_chains if TYPE_CHECKING: - from qntx.openai._chains._types import EvmConfig, SvmConfig, TvmConfig + from x402_openai._chains._types import EvmConfig, SvmConfig, TvmConfig Policy = Callable[[int, list[Any]], list[Any]] Selector = Callable[[int, list[Any]], Any] diff --git a/src/qntx/openai/_policies.py b/src/x402_openai/_policies.py similarity index 95% rename from src/qntx/openai/_policies.py rename to src/x402_openai/_policies.py index 260f151..9b1235d 100644 --- a/src/qntx/openai/_policies.py +++ b/src/x402_openai/_policies.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Any if TYPE_CHECKING: - from qntx.openai._payments import Policy + from x402_openai._payments import Policy def prefer_network(network: str) -> Policy: diff --git a/src/qntx/openai/_transport.py b/src/x402_openai/_transport.py similarity index 99% rename from src/qntx/openai/_transport.py rename to src/x402_openai/_transport.py index 1707b31..83d6599 100644 --- a/src/qntx/openai/_transport.py +++ b/src/x402_openai/_transport.py @@ -17,7 +17,7 @@ from x402.http import x402HTTPClient, x402HTTPClientSync -logger = logging.getLogger("qntx.openai") +logger = logging.getLogger("x402_openai") RETRY_KEY = "_x402_is_retry" RECOVERY_KEY = "_x402_is_recovery" diff --git a/src/qntx/openai/py.typed b/src/x402_openai/py.typed similarity index 100% rename from src/qntx/openai/py.typed rename to src/x402_openai/py.typed diff --git a/tests/test_chains_evm.py b/tests/test_chains_evm.py index ce6e6af..6374d33 100644 --- a/tests/test_chains_evm.py +++ b/tests/test_chains_evm.py @@ -10,10 +10,10 @@ from x402.mechanisms.evm.signers import EthAccountSignerWithRPC from x402.mechanisms.evm.upto import UptoEvmScheme -from qntx.openai._chains._evm import register_evm -from qntx.openai._chains._register import register_chains -from qntx.openai._chains._types import EvmConfig -from qntx.openai._payments import PaymentSourceOptions, build_x402_client +from x402_openai._chains._evm import register_evm +from x402_openai._chains._register import register_chains +from x402_openai._chains._types import EvmConfig +from x402_openai._payments import PaymentSourceOptions, build_x402_client EVM_KEY = "0xac0974dac38f24671676c33098b7abf185c4d7b8d04844c06a56a24126c6dcbd" diff --git a/tests/test_chains_svm.py b/tests/test_chains_svm.py index 162a982..44842fc 100644 --- a/tests/test_chains_svm.py +++ b/tests/test_chains_svm.py @@ -9,11 +9,11 @@ from x402.mechanisms.svm.exact import ExactSvmScheme from x402.schemas import PaymentRequired, PaymentRequirements, ResourceInfo -from qntx.openai import prefer_scheme -from qntx.openai._chains._register import register_chains -from qntx.openai._chains._svm import register_svm -from qntx.openai._chains._types import SvmConfig -from qntx.openai._payments import PaymentSourceOptions, build_x402_client +from x402_openai import prefer_scheme +from x402_openai._chains._register import register_chains +from x402_openai._chains._svm import register_svm +from x402_openai._chains._types import SvmConfig +from x402_openai._payments import PaymentSourceOptions, build_x402_client # 64-byte Ed25519 secret (seed + pubkey), base58. Seed is 31 zero bytes + 0x01. SVM_KEY = "1111111111111111111111111111111PPm2a2NNZH2EFJ5UkEjkH9Fcxn8cvjTmZDKQQisyLDmA" diff --git a/tests/test_chains_tvm.py b/tests/test_chains_tvm.py index 766bdb6..fe60f11 100644 --- a/tests/test_chains_tvm.py +++ b/tests/test_chains_tvm.py @@ -6,10 +6,10 @@ import pytest -from qntx.openai._chains._register import register_chains -from qntx.openai._chains._tvm import register_tvm -from qntx.openai._chains._types import TvmConfig -from qntx.openai._payments import PaymentSourceOptions, build_x402_client +from x402_openai._chains._register import register_chains +from x402_openai._chains._tvm import register_tvm +from x402_openai._chains._types import TvmConfig +from x402_openai._payments import PaymentSourceOptions, build_x402_client TVM_KEY = "11" * 32 @@ -194,7 +194,7 @@ def test_invalid_key_is_not_missing_extra() -> None: with pytest.raises(ValueError) as exc: register_tvm(client, TvmConfig(private_key="00")) # type: ignore[arg-type] assert "not installed" not in str(exc.value) - assert "qntx-openai[tvm]" not in str(exc.value) + assert "x402-openai[tvm]" not in str(exc.value) def test_dispose_mocks_real_scheme_close(monkeypatch: pytest.MonkeyPatch) -> None: diff --git a/tests/test_client.py b/tests/test_client.py index f2426da..0d7a0ec 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -11,9 +11,9 @@ import pytest from x402 import x402Client, x402ClientSync -import qntx.openai as api -from qntx.openai import AsyncX402OpenAI, SvmConfig, TvmConfig, X402OpenAI -from qntx.openai._payments import BuiltClient +import x402_openai as api +from x402_openai import AsyncX402OpenAI, SvmConfig, TvmConfig, X402OpenAI +from x402_openai._payments import BuiltClient EVM_KEY = "0xac0974dac38f24671676c33098b7abf185c4d7b8d04844c06a56a24126c6dcbd" TVM_KEY = "11" * 32 @@ -45,7 +45,7 @@ def test_throws_on_empty_evm_string() -> None: def test_throws_on_empty_evm_config() -> None: - from qntx.openai import EvmConfig + from x402_openai import EvmConfig with pytest.raises(ValueError, match="non-empty"): X402OpenAI(evm=EvmConfig(private_key="")) @@ -57,7 +57,7 @@ def test_throws_on_empty_svm_string() -> None: def test_throws_on_empty_svm_config() -> None: - from qntx.openai import SvmConfig + from x402_openai import SvmConfig with pytest.raises(ValueError, match="'svm' private key must be a non-empty string"): X402OpenAI(svm=SvmConfig(private_key="")) @@ -209,7 +209,7 @@ def run_ensure() -> None: except BaseException as e: errors.append(e) - with patch("qntx.openai._client.build_x402_client", fake_build): + with patch("x402_openai._client.build_x402_client", fake_build): thread = threading.Thread(target=run_ensure) thread.start() assert built_started.wait(timeout=2) @@ -231,7 +231,7 @@ def fake_build(options: object, *, sync: bool) -> BuiltClient: return BuiltClient(http=object(), dispose=lambda: None) client = AsyncX402OpenAI(evm=EVM_KEY) - with patch("qntx.openai._client.build_x402_client", fake_build): + with patch("x402_openai._client.build_x402_client", fake_build): h1, h2 = await asyncio.gather( client._lifecycle._ensure_http(), client._lifecycle._ensure_http(), @@ -340,7 +340,7 @@ def fake_build(options: object, *, sync: bool) -> BuiltClient: await lifecycle._lock.acquire() try: - with patch("qntx.openai._client.build_x402_client", fake_build): + with patch("x402_openai._client.build_x402_client", fake_build): ensure_task = asyncio.create_task(lifecycle._ensure_http()) await asyncio.sleep(0) close_task = asyncio.create_task(client.close()) @@ -371,7 +371,7 @@ def fake_build(options: object, *, sync: bool) -> BuiltClient: return BuiltClient(http=object(), dispose=dispose) with ( - patch("qntx.openai._client.build_x402_client", fake_build), + patch("x402_openai._client.build_x402_client", fake_build), pytest.raises(RuntimeError, match="X402OpenAI is closed"), ): await lifecycle._ensure_http() @@ -387,9 +387,9 @@ def capturing_transport(*args: Any, **kwargs: Any) -> httpx2.HTTPTransport: captured.append(kwargs) return real(*args, **kwargs) - monkeypatch.setattr("qntx.openai._client.httpx2.HTTPTransport", capturing_transport) + monkeypatch.setattr("x402_openai._client.httpx2.HTTPTransport", capturing_transport) monkeypatch.setattr( - "qntx.openai._client.get_environment_proxies", + "x402_openai._client.get_environment_proxies", lambda: {"https://": "http://proxy.example:8080"}, ) X402OpenAI(evm="0x1") diff --git a/tests/test_missing_extra.py b/tests/test_missing_extra.py index e49cd9c..02577f3 100644 --- a/tests/test_missing_extra.py +++ b/tests/test_missing_extra.py @@ -4,7 +4,7 @@ import pytest -from qntx.openai._chains._types import EvmConfig, SvmConfig, TvmConfig +from x402_openai._chains._types import EvmConfig, SvmConfig, TvmConfig def test_missing_evm_extra_import_error(monkeypatch: pytest.MonkeyPatch) -> None: @@ -14,13 +14,13 @@ def test_missing_evm_extra_import_error(monkeypatch: pytest.MonkeyPatch) -> None if name.startswith("eth_account.") or name.startswith("x402.mechanisms.evm."): monkeypatch.setitem(sys.modules, name, None) - from qntx.openai._chains._evm import register_evm + from x402_openai._chains._evm import register_evm class _Client: def register(self, network: str, scheme: object) -> None: return None - with pytest.raises(ImportError, match=r"qntx-openai\[evm\]"): + with pytest.raises(ImportError, match=r"x402-openai\[evm\]"): register_evm(_Client(), EvmConfig(private_key="0x1")) # type: ignore[arg-type] @@ -33,13 +33,13 @@ def test_missing_svm_extra_import_error(monkeypatch: pytest.MonkeyPatch) -> None if name == "x402.mechanisms.svm" or name.startswith("x402.mechanisms.svm."): monkeypatch.setitem(sys.modules, name, None) - from qntx.openai._chains._svm import register_svm + from x402_openai._chains._svm import register_svm class _Client: def register(self, network: str, scheme: object) -> None: return None - with pytest.raises(ImportError, match=r"qntx-openai\[svm\]"): + with pytest.raises(ImportError, match=r"x402-openai\[svm\]"): register_svm(_Client(), SvmConfig(private_key="base58")) # type: ignore[arg-type] @@ -55,11 +55,11 @@ def test_missing_tvm_extra_import_error(monkeypatch: pytest.MonkeyPatch) -> None ): monkeypatch.setitem(sys.modules, name, None) - from qntx.openai._chains._tvm import register_tvm + from x402_openai._chains._tvm import register_tvm class _Client: def register(self, network: str, scheme: object) -> None: return None - with pytest.raises(ImportError, match=r"qntx-openai\[tvm\]"): + with pytest.raises(ImportError, match=r"x402-openai\[tvm\]"): register_tvm(_Client(), TvmConfig(private_key="11" * 32)) # type: ignore[arg-type] diff --git a/tests/test_payments.py b/tests/test_payments.py index a7d7803..2b81125 100644 --- a/tests/test_payments.py +++ b/tests/test_payments.py @@ -8,9 +8,9 @@ from x402.http import x402HTTPClient, x402HTTPClientSync from x402.schemas import PaymentRequired, PaymentRequirements, ResourceInfo -from qntx.openai._chains._register import ChainHandles -from qntx.openai._chains._types import EvmConfig, SvmConfig, TvmConfig -from qntx.openai._payments import ( +from x402_openai._chains._register import ChainHandles +from x402_openai._chains._types import EvmConfig, SvmConfig, TvmConfig +from x402_openai._payments import ( PREBUILT_EXCLUSIVE, PaymentSourceOptions, assert_payment_options, @@ -176,8 +176,8 @@ def set_spend_controls(self, controls: object) -> Any: return super().set_spend_controls(controls) # type: ignore[misc] with ( - patch("qntx.openai._payments.x402ClientSync", _Client), - patch("qntx.openai._payments.register_chains", _noop_register), + patch("x402_openai._payments.x402ClientSync", _Client), + patch("x402_openai._payments.register_chains", _noop_register), ): build_x402_client(PaymentSourceOptions(evm=EVM_KEY), sync=True) assert calls == [] @@ -192,8 +192,8 @@ def set_spend_controls(self, controls: object) -> Any: return super().set_spend_controls(controls) # type: ignore[misc] with ( - patch("qntx.openai._payments.x402ClientSync", _Client), - patch("qntx.openai._payments.register_chains", _noop_register), + patch("x402_openai._payments.x402ClientSync", _Client), + patch("x402_openai._payments.register_chains", _noop_register), ): build_x402_client(PaymentSourceOptions(evm=EVM_KEY, spend_controls=False), sync=True) assert calls == [False] @@ -205,7 +205,7 @@ def _core(built: object) -> x402ClientSync: def test_spend_controls_omitted_rejects_2_usdc() -> None: - with patch("qntx.openai._payments.register_chains", _noop_register): + with patch("x402_openai._payments.register_chains", _noop_register): built = build_x402_client(PaymentSourceOptions(evm=EVM_KEY), sync=True) core = _core(built) core.register("eip155:8453", StubUsdcScheme("exact")) @@ -214,7 +214,7 @@ def test_spend_controls_omitted_rejects_2_usdc() -> None: def test_spend_controls_explicit_1_rejects_2_usdc() -> None: - with patch("qntx.openai._payments.register_chains", _noop_register): + with patch("x402_openai._payments.register_chains", _noop_register): built = build_x402_client( PaymentSourceOptions(evm=EVM_KEY, spend_controls={"max_amount_per_payment": "$1"}), sync=True, @@ -226,7 +226,7 @@ def test_spend_controls_explicit_1_rejects_2_usdc() -> None: def test_spend_controls_5_allows_2_usdc() -> None: - with patch("qntx.openai._payments.register_chains", _noop_register): + with patch("x402_openai._payments.register_chains", _noop_register): built = build_x402_client( PaymentSourceOptions(evm=EVM_KEY, spend_controls={"max_amount_per_payment": "$5"}), sync=True, @@ -238,7 +238,7 @@ def test_spend_controls_5_allows_2_usdc() -> None: def test_spend_controls_false_allows_2_usdc() -> None: - with patch("qntx.openai._payments.register_chains", _noop_register): + with patch("x402_openai._payments.register_chains", _noop_register): built = build_x402_client( PaymentSourceOptions(evm=EVM_KEY, spend_controls=False), sync=True ) @@ -249,10 +249,10 @@ def test_spend_controls_false_allows_2_usdc() -> None: def test_build_registers_policies() -> None: - from qntx.openai import prefer_scheme + from x402_openai import prefer_scheme policy = prefer_scheme("upto") - with patch("qntx.openai._payments.register_chains", _noop_register): + with patch("x402_openai._payments.register_chains", _noop_register): built = build_x402_client( PaymentSourceOptions(evm=EVM_KEY, policies=[policy]), sync=True, @@ -262,7 +262,7 @@ def test_build_registers_policies() -> None: def test_selector_runs_after_spend_controls() -> None: - with patch("qntx.openai._payments.register_chains", _noop_register): + with patch("x402_openai._payments.register_chains", _noop_register): built = build_x402_client( PaymentSourceOptions( evm=EVM_KEY, diff --git a/tests/test_policies.py b/tests/test_policies.py index ddb5657..d1b919e 100644 --- a/tests/test_policies.py +++ b/tests/test_policies.py @@ -2,7 +2,7 @@ from typing import Any, NamedTuple -from qntx.openai import prefer_network, prefer_scheme +from x402_openai import prefer_network, prefer_scheme class _Req(NamedTuple): diff --git a/tests/test_transport.py b/tests/test_transport.py index e410eb4..2ed2e87 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -9,7 +9,7 @@ import httpx2 import pytest -from qntx.openai._transport import ( +from x402_openai._transport import ( RECOVERY_KEY, RETRY_KEY, PaymentError, diff --git a/uv.lock b/uv.lock index dcdc71c..719efa8 100644 --- a/uv.lock +++ b/uv.lock @@ -1750,64 +1750,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] -[[package]] -name = "qntx-openai" -version = "1.0.0" -source = { editable = "." } -dependencies = [ - { name = "httpx2" }, - { name = "openai" }, - { name = "x402" }, -] - -[package.optional-dependencies] -all = [ - { name = "eth-account" }, - { name = "solana" }, - { name = "x402", extra = ["evm", "svm", "tvm"] }, -] -dev = [ - { name = "build" }, - { name = "mypy" }, - { name = "pre-commit" }, - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "ruff" }, -] -evm = [ - { name = "eth-account" }, - { name = "x402", extra = ["evm"] }, -] -svm = [ - { name = "solana" }, - { name = "x402", extra = ["svm"] }, -] -tvm = [ - { name = "x402", extra = ["tvm"] }, -] - -[package.metadata] -requires-dist = [ - { name = "build", marker = "extra == 'dev'", specifier = ">=1.0" }, - { name = "eth-account", marker = "extra == 'evm'", specifier = ">=0.13.0" }, - { name = "httpx2", specifier = ">=2.12.0" }, - { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.0" }, - { name = "openai", specifier = ">=3.7.0" }, - { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=4.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" }, - { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.24" }, - { name = "qntx-openai", extras = ["evm"], marker = "extra == 'all'" }, - { name = "qntx-openai", extras = ["svm"], marker = "extra == 'all'" }, - { name = "qntx-openai", extras = ["tvm"], marker = "extra == 'all'" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.8" }, - { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0,<0.40" }, - { name = "x402", specifier = ">=2.21.0" }, - { name = "x402", extras = ["evm"], marker = "extra == 'evm'", specifier = ">=2.21.0" }, - { name = "x402", extras = ["svm"], marker = "extra == 'svm'", specifier = ">=2.21.0" }, - { name = "x402", extras = ["tvm"], marker = "extra == 'tvm'", specifier = ">=2.21.0" }, -] -provides-extras = ["evm", "svm", "tvm", "all", "dev"] - [[package]] name = "regex" version = "2026.1.15" @@ -2274,6 +2216,64 @@ tvm = [ { name = "pytoniq-core" }, ] +[[package]] +name = "x402-openai" +version = "1.0.0" +source = { editable = "." } +dependencies = [ + { name = "httpx2" }, + { name = "openai" }, + { name = "x402" }, +] + +[package.optional-dependencies] +all = [ + { name = "eth-account" }, + { name = "solana" }, + { name = "x402", extra = ["evm", "svm", "tvm"] }, +] +dev = [ + { name = "build" }, + { name = "mypy" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, +] +evm = [ + { name = "eth-account" }, + { name = "x402", extra = ["evm"] }, +] +svm = [ + { name = "solana" }, + { name = "x402", extra = ["svm"] }, +] +tvm = [ + { name = "x402", extra = ["tvm"] }, +] + +[package.metadata] +requires-dist = [ + { name = "build", marker = "extra == 'dev'", specifier = ">=1.0" }, + { name = "eth-account", marker = "extra == 'evm'", specifier = ">=0.13.0" }, + { name = "httpx2", specifier = ">=2.12.0" }, + { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.0" }, + { name = "openai", specifier = ">=3.7.0" }, + { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=4.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.24" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.8" }, + { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0,<0.40" }, + { name = "x402", specifier = ">=2.21.0" }, + { name = "x402", extras = ["evm"], marker = "extra == 'evm'", specifier = ">=2.21.0" }, + { name = "x402", extras = ["svm"], marker = "extra == 'svm'", specifier = ">=2.21.0" }, + { name = "x402", extras = ["tvm"], marker = "extra == 'tvm'", specifier = ">=2.21.0" }, + { name = "x402-openai", extras = ["evm"], marker = "extra == 'all'" }, + { name = "x402-openai", extras = ["svm"], marker = "extra == 'all'" }, + { name = "x402-openai", extras = ["tvm"], marker = "extra == 'all'" }, +] +provides-extras = ["evm", "svm", "tvm", "all", "dev"] + [[package]] name = "yarl" version = "1.22.0"