Warning: Permanently added '18.206.176.37' (ED25519) to the list of known hosts. You can reproduce this build on your computer by running: sudo dnf install copr-rpmbuild /usr/bin/copr-rpmbuild --verbose --drop-resultdir --task-url https://copr.fedorainfracloud.org/backend/get-build-task/11121911-fedora-rawhide-x86_64 --chroot fedora-rawhide-x86_64 Version: 1.10 PID: 61358 Logging PID: 61360 Task: {'allow_user_ssh': False, 'appstream': False, 'background': False, 'build_id': 11121911, 'buildroot_pkgs': [], 'chroot': 'fedora-rawhide-x86_64', 'enable_net': False, 'fedora_review': False, 'git_hash': '205d58cf4a00a7cd2c40fe81771ab03349fac028', 'git_repo': 'https://copr-dist-git.fedorainfracloud.org/git/music/pydantic-rawhide/python-llm', 'isolation': 'default', 'memory_reqs': 2048, 'package_name': 'python-llm', 'package_version': '0.34-1', 'project_dirname': 'pydantic-rawhide', 'project_name': 'pydantic-rawhide', 'project_owner': 'music', 'repo_priority': None, 'repos': [{'baseurl': 'https://download.copr.fedorainfracloud.org/results/music/pydantic-rawhide/fedora-rawhide-x86_64/', 'id': 'copr_base', 'name': 'Copr repository', 'priority': None, 'repo_gpgcheck': False}], 'sandbox': 'music/pydantic-rawhide--music', 'source_json': {}, 'source_type': None, 'ssh_public_keys': None, 'storage': 1, 'submitter': 'music', 'tags': [], 'task_id': '11121911-fedora-rawhide-x86_64', 'timeout': 18000, 'uses_devel_repo': False, 'with_opts': [], 'without_opts': []} Running: git clone https://copr-dist-git.fedorainfracloud.org/git/music/pydantic-rawhide/python-llm /var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm --depth 500 --no-single-branch --recursive cmd: ['git', 'clone', 'https://copr-dist-git.fedorainfracloud.org/git/music/pydantic-rawhide/python-llm', '/var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm', '--depth', '500', '--no-single-branch', '--recursive'] cwd: . rc: 0 stdout: stderr: Cloning into '/var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm'... Running: git checkout 205d58cf4a00a7cd2c40fe81771ab03349fac028 -- cmd: ['git', 'checkout', '205d58cf4a00a7cd2c40fe81771ab03349fac028', '--'] cwd: /var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm rc: 0 stdout: stderr: Note: switching to '205d58cf4a00a7cd2c40fe81771ab03349fac028'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command. Example: git switch -c Or undo this operation with: git switch - Turn off this advice by setting config variable advice.detachedHead to false HEAD is now at 205d58c automatic import of python-llm Running: dist-git-client sources cmd: ['dist-git-client', 'sources'] cwd: /var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm rc: 0 stdout: stderr: INFO: Reading stdout from command: git rev-parse --abbrev-ref HEAD INFO: Reading stdout from command: git rev-parse HEAD INFO: Reading sources specification file: sources INFO: Downloading llm-0.34.tar.gz INFO: Reading stdout from command: curl --help all INFO: Calling: curl -H Pragma: -H 'Accept-Encoding: identity' -o llm-0.34.tar.gz --location --connect-timeout 60 --retry 3 --retry-delay 10 --remote-time --show-error --fail --retry-all-errors https://copr-dist-git.fedorainfracloud.org/repo/pkgs/music/pydantic-rawhide/python-llm/llm-0.34.tar.gz/md5/370d757bebef71339937d62757107677/llm-0.34.tar.gz % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 425.8k 100 425.8k 0 0 29.75M 0 0 INFO: Reading stdout from command: md5sum llm-0.34.tar.gz tail: /var/lib/copr-rpmbuild/main.log: file truncated Running (timeout=18000): unbuffer mock --spec /var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm/python-llm.spec --sources /var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm --resultdir /var/lib/copr-rpmbuild/results --uniqueext 1791974115.829543 -r /var/lib/copr-rpmbuild/results/configs/child.cfg INFO: mock.py version 6.9 starting (python version = 3.14.5, NVR = mock-6.9-1.fc44), args: /usr/libexec/mock/mock --spec /var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm/python-llm.spec --sources /var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm --resultdir /var/lib/copr-rpmbuild/results --uniqueext 1791974115.829543 -r /var/lib/copr-rpmbuild/results/configs/child.cfg Start(bootstrap): init plugins INFO: tmpfs initialized INFO: selinux enabled INFO: chroot_scan: initialized INFO: compress_logs: initialized Finish(bootstrap): init plugins Start: init plugins INFO: tmpfs initialized INFO: selinux enabled INFO: chroot_scan: initialized INFO: compress_logs: initialized Finish: init plugins INFO: Signal handler active Start: run INFO: Start(/var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm/python-llm.spec) Config(fedora-rawhide-x86_64) Start: clean chroot Finish: clean chroot Mock Version: 6.9 INFO: Mock Version: 6.9 Start(bootstrap): chroot init INFO: mounting tmpfs at /var/lib/mock/fedora-rawhide-x86_64-bootstrap-1791974115.829543/root. INFO: calling preinit hooks INFO: enabled root cache INFO: enabled package manager cache Start(bootstrap): cleaning package manager metadata Finish(bootstrap): cleaning package manager metadata INFO: Guessed host environment type: unknown INFO: Using container image: registry.fedoraproject.org/fedora:rawhide INFO: Pulling image: registry.fedoraproject.org/fedora:rawhide INFO: Tagging container image as mock-bootstrap-27749c75-52e7-4786-b7b1-d04061dffc32 INFO: Checking that e31698a7ca946e9c9926ddfdfb7fa740c646358f46bf2af6216e35b3e5e33808 image matches host's architecture INFO: Copy content of container e31698a7ca946e9c9926ddfdfb7fa740c646358f46bf2af6216e35b3e5e33808 to /var/lib/mock/fedora-rawhide-x86_64-bootstrap-1791974115.829543/root INFO: mounting e31698a7ca946e9c9926ddfdfb7fa740c646358f46bf2af6216e35b3e5e33808 with podman image mount INFO: image e31698a7ca946e9c9926ddfdfb7fa740c646358f46bf2af6216e35b3e5e33808 as /var/lib/containers/storage/overlay/d863205d7ebfc6405e32b4ef20d23230e32818032120aa0337b9b25c62e307a1/merged INFO: umounting image e31698a7ca946e9c9926ddfdfb7fa740c646358f46bf2af6216e35b3e5e33808 (/var/lib/containers/storage/overlay/d863205d7ebfc6405e32b4ef20d23230e32818032120aa0337b9b25c62e307a1/merged) with podman image umount INFO: Removing image mock-bootstrap-27749c75-52e7-4786-b7b1-d04061dffc32 INFO: Package manager dnf5 detected and used (fallback) INFO: Not updating bootstrap chroot, bootstrap_image_ready=True Start(bootstrap): creating root cache Finish(bootstrap): creating root cache Finish(bootstrap): chroot init Start: chroot init INFO: mounting tmpfs at /var/lib/mock/fedora-rawhide-x86_64-1791974115.829543/root. INFO: calling preinit hooks INFO: enabled root cache INFO: enabled package manager cache Start: cleaning package manager metadata Finish: cleaning package manager metadata INFO: enabled HW Info plugin INFO: Package manager dnf5 detected and used (direct choice) INFO: Buildroot is handled by package management downloaded with a bootstrap image: rpm-6.1.0-1.fc46.x86_64 rpm-sequoia-1.10.3-1.fc46.x86_64 dnf5-5.4.6.0-1.fc46.x86_64 dnf5-plugins-5.4.6.0-1.fc46.x86_64 Start: installing minimal buildroot with dnf5 Updating and loading repositories: fedora 100% | 106.4 KiB/s | 24.6 KiB | 00m00s Copr repository 100% | 9.9 KiB/s | 1.5 KiB | 00m00s Repositories loaded. Package Arch Version Repository Size Installing group/module packages: bash x86_64 0:5.3.20-1.fc46 fedora 8.5 MiB bzip2 x86_64 0:1.0.8-24.fc45 fedora 95.0 KiB coreutils x86_64 0:9.12-1.fc46 fedora 6.3 MiB cpio x86_64 0:2.15-10.fc45 fedora 1.1 MiB diffutils x86_64 0:3.12-6.fc45 fedora 1.6 MiB fedora-release-common noarch 0:46-0.1 fedora 4.6 KiB findutils x86_64 1:4.11.0-2.fc45 fedora 1.9 MiB gawk x86_64 0:5.4.1-1.fc45 fedora 2.2 MiB glibc-minimal-langpack x86_64 0:2.44.9000-5.fc46 fedora 0.0 B grep x86_64 0:3.12-4.fc45 fedora 1.0 MiB gzip x86_64 0:1.15-1.fc46 fedora 445.2 KiB info x86_64 0:7.3-3.fc45 fedora 372.4 KiB patch x86_64 0:2.8-6.fc46 fedora 226.6 KiB redhat-rpm-config noarch 0:345-4.fc46 fedora 184.2 KiB rpm-build x86_64 0:6.1.0-1.fc46 fedora 312.1 KiB sed x86_64 0:4.10-2.fc45 fedora 866.5 KiB shadow-utils x86_64 2:4.20.0-1.fc45 fedora 3.9 MiB tar x86_64 2:1.35-9.fc45 fedora 3.0 MiB unzip x86_64 0:6.0-71.fc45 fedora 441.8 KiB util-linux x86_64 0:2.42.4-2.fc46 fedora 3.7 MiB which x86_64 0:2.25-2.fc45 fedora 83.6 KiB xz x86_64 1:5.8.4-1.fc46 fedora 1.4 MiB Installing dependencies: R-srpm-macros noarch 0:1.3.7-3.fc45 fedora 3.5 KiB add-determinism x86_64 0:0.7.3-3.fc45 fedora 2.2 MiB alternatives x86_64 0:1.33-6.fc45 fedora 62.1 KiB ansible-srpm-macros noarch 0:1-22.fc45 fedora 35.7 KiB audit-libs x86_64 0:4.2.1-2.fc45 fedora 390.5 KiB binutils x86_64 0:2.47.50-15.fc46 fedora 24.5 MiB build-reproducibility-srpm-macros noarch 0:0.7.3-3.fc45 fedora 1.2 KiB bzip2-libs x86_64 0:1.0.8-24.fc45 fedora 80.5 KiB ca-certificates noarch 0:2026.2.90_v9.0.317-1.fc46 fedora 2.6 MiB cmake-srpm-macros noarch 0:4.3.0-5.fc45 fedora 524.0 B coreutils-common x86_64 0:9.12-1.fc46 fedora 11.5 MiB crypto-policies noarch 0:20260713-2.gitc42da77.fc45 fedora 134.3 KiB curl x86_64 0:8.23.0~rc3-1.fc46 fedora 486.1 KiB cyrus-sasl-lib x86_64 0:2.1.28-37.fc45 fedora 2.3 MiB debugedit x86_64 0:5.3-3.fc45 fedora 220.8 KiB dwz x86_64 0:0.17-3.fc45 fedora 291.1 KiB ed x86_64 0:1.22.6-1.fc46 fedora 150.9 KiB efi-srpm-macros noarch 0:6-9.fc45 fedora 40.3 KiB elfutils x86_64 0:0.196-1.fc46 fedora 3.2 MiB elfutils-debuginfod-client x86_64 0:0.196-1.fc46 fedora 79.9 KiB elfutils-libelf x86_64 0:0.196-1.fc46 fedora 1.4 MiB elfutils-libs x86_64 0:0.196-1.fc46 fedora 719.6 KiB erlang-srpm-macros noarch 0:0.4.0-1.fc46 fedora 2.0 KiB fedora-gpg-keys noarch 0:46-0.3 fedora 130.3 KiB fedora-release noarch 0:46-0.1 fedora 0.0 B fedora-release-identity-basic noarch 0:46-0.1 fedora 664.0 B fedora-repos noarch 0:46-0.3 fedora 4.9 KiB fedora-repos-rawhide noarch 0:46-0.3 fedora 2.2 KiB file x86_64 0:5.48-3.fc46 fedora 101.9 KiB file-libs x86_64 0:5.48-3.fc46 fedora 12.3 MiB filesystem x86_64 0:3.18-59.fc45 fedora 112.0 B filesystem-srpm-macros noarch 0:3.18-59.fc45 fedora 38.2 KiB fips-provider x86_64 0:1.5.3-1.fc46 fedora 4.8 MiB fonts-srpm-macros noarch 1:5.0.0-4.fc45 fedora 55.8 KiB forge-srpm-macros noarch 0:0.4.0-5.fc45 fedora 38.9 KiB fpc-srpm-macros noarch 0:1.3-17.fc45 fedora 144.0 B gap-srpm-macros noarch 0:2-3.fc45 fedora 2.1 KiB gdb-minimal x86_64 0:17.2-6.fc46 fedora 14.2 MiB gdbm-libs x86_64 1:1.26-1.fc46 fedora 134.2 KiB ghc-srpm-macros noarch 0:1.10-2.fc45 fedora 792.0 B glibc x86_64 0:2.44.9000-5.fc46 fedora 7.2 MiB glibc-common x86_64 0:2.44.9000-5.fc46 fedora 1.0 MiB glibc-gconv-extra x86_64 0:2.44.9000-5.fc46 fedora 7.7 MiB gmp x86_64 1:6.3.0-6.fc45 fedora 815.2 KiB gnat-srpm-macros noarch 0:7-3.fc45 fedora 1.0 KiB gnome-srpm-macros noarch 0:1.0-2.fc45 fedora 3.5 KiB gnulib-l10n noarch 0:20241231-4.fc45 fedora 655.0 KiB gnupg2 x86_64 0:2.4.9-18.fc45 fedora 6.5 MiB gnupg2-dirmngr x86_64 0:2.4.9-18.fc45 fedora 630.1 KiB gnupg2-gpg-agent x86_64 0:2.4.9-18.fc45 fedora 678.8 KiB gnupg2-gpgconf x86_64 0:2.4.9-18.fc45 fedora 253.8 KiB gnupg2-keyboxd x86_64 0:2.4.9-18.fc45 fedora 201.3 KiB gnupg2-verify x86_64 0:2.4.9-18.fc45 fedora 356.3 KiB gnutls x86_64 0:3.8.13-5.fc46 fedora 3.8 MiB go-srpm-macros noarch 0:3.8.0-3.fc45 fedora 61.9 KiB gpgverify noarch 0:2.2-5.fc45 fedora 8.7 KiB ima-evm-utils-libs x86_64 0:1.6.2-12.fc45 fedora 56.6 KiB jansson x86_64 0:2.14-5.fc45 fedora 89.0 KiB java-srpm-macros noarch 0:1-9.fc45 fedora 870.0 B json-c x86_64 0:0.18-9.fc45 fedora 82.7 KiB kernel-srpm-macros noarch 0:1.0-30.fc45 fedora 1.9 KiB keyutils-libs x86_64 0:1.6.3-8.fc45 fedora 54.2 KiB krb5-libs x86_64 0:1.22.2-9.fc45 fedora 2.4 MiB libacl x86_64 0:2.4.0-2.fc45 fedora 43.9 KiB libarchive x86_64 0:3.8.9-2.fc46 fedora 1.0 MiB libassuan x86_64 0:2.5.7-6.fc45 fedora 163.9 KiB libattr x86_64 0:2.6.0-2.fc45 fedora 24.3 KiB libblkid x86_64 0:2.42.4-2.fc46 fedora 282.3 KiB libbrotli x86_64 0:1.2.0-6.fc45 fedora 865.0 KiB libcap x86_64 0:2.78-2.fc45 fedora 208.2 KiB libcap-ng x86_64 0:0.9.6-1.fc46 fedora 68.8 KiB libcbor x86_64 0:0.14.0-3.fc45 fedora 83.5 KiB libcom_err x86_64 0:1.47.4-2.fc45 fedora 63.0 KiB libcurl x86_64 0:8.23.0~rc3-1.fc46 fedora 1.1 MiB libeconf x86_64 0:0.7.9-4.fc45 fedora 64.8 KiB libevent x86_64 0:2.1.13-1.fc46 fedora 980.7 KiB libfdisk x86_64 0:2.42.4-2.fc46 fedora 392.3 KiB libffi x86_64 0:3.8.0-1.fc46 fedora 95.5 KiB libfido2 x86_64 0:1.17.0-6.fc46 fedora 256.5 KiB libfsverity x86_64 0:1.7-4.fc45 fedora 24.4 KiB libgcc x86_64 0:16.2.1-2.fc46.1 fedora 270.7 KiB libgcrypt x86_64 0:1.12.4-1.fc46 fedora 1.7 MiB libgomp x86_64 0:16.2.1-2.fc46.1 fedora 577.5 KiB libgpg-error x86_64 0:1.61-2.fc45 fedora 953.9 KiB libidn2 x86_64 0:2.3.8-4.fc45 fedora 556.4 KiB libksba x86_64 0:1.8.1-1.fc46 fedora 431.9 KiB liblastlog2 x86_64 0:2.42.4-2.fc46 fedora 37.6 KiB libmount x86_64 0:2.42.4-2.fc46 fedora 408.9 KiB libnghttp2 x86_64 0:1.69.0-6.fc46 fedora 166.1 KiB libnghttp3 x86_64 0:1.18.0-1.fc45 fedora 163.4 KiB libpfm x86_64 0:4.13.0-23.fc45 fedora 1.7 MiB libpkgconf x86_64 0:2.5.1-2.fc45 fedora 90.1 KiB libpsl x86_64 0:0.23.3-1.fc46 fedora 80.4 KiB libselinux x86_64 0:3.11-5.fc46 fedora 205.2 KiB libselinux-utils x86_64 0:3.11-5.fc46 fedora 306.0 KiB libsemanage x86_64 0:3.11-4.fc46 fedora 320.6 KiB libsepol x86_64 0:3.11-2.fc45 fedora 866.1 KiB libsmartcols x86_64 0:2.42.4-2.fc46 fedora 188.5 KiB libssh x86_64 0:0.12.2-1.fc45 fedora 725.7 KiB libssh-config noarch 0:0.12.2-1.fc45 fedora 277.0 B libstdc++ x86_64 0:16.2.1-2.fc46.1 fedora 3.1 MiB libtasn1 x86_64 0:4.21.0-2.fc45 fedora 176.6 KiB libtool-ltdl x86_64 0:2.6.2-1.fc46 fedora 70.0 KiB libunistring x86_64 0:1.1-12.fc45 fedora 1.7 MiB libusb1 x86_64 0:1.0.30-2.fc45 fedora 180.1 KiB libuuid x86_64 0:2.42.4-2.fc46 fedora 37.2 KiB libverto x86_64 0:0.3.2-13.fc45 fedora 25.3 KiB libxcrypt x86_64 0:4.5.2-4.fc45 fedora 293.2 KiB libxml2 x86_64 0:2.15.4-1.fc46 fedora 1.7 MiB libzstd x86_64 0:1.5.7-6.fc45 fedora 956.1 KiB linkdupes x86_64 0:0.7.3-3.fc45 fedora 782.1 KiB lua-libs x86_64 0:5.5.1-2.fc46 fedora 298.0 KiB lua-srpm-macros noarch 0:1-18.fc45 fedora 1.3 KiB lz4-libs x86_64 0:1.10.0-5.fc45 fedora 165.3 KiB meson-srpm-macros noarch 0:1.12.1-2.fc46 fedora 1.7 KiB mpfr x86_64 0:4.2.2-4.fc45 fedora 849.2 KiB ncurses-base noarch 0:6.6-3.fc45 fedora 329.7 KiB ncurses-libs x86_64 0:6.6-3.fc45 fedora 969.1 KiB nettle x86_64 0:4.0-5.fc45 fedora 801.9 KiB ngtcp2 x86_64 0:1.22.1-3.fc45 fedora 334.3 KiB ngtcp2-crypto-ossl x86_64 0:1.22.1-3.fc45 fedora 51.6 KiB npth x86_64 0:1.8-5.fc45 fedora 49.5 KiB ocaml-srpm-macros noarch 0:11-4.fc45 fedora 1.9 KiB openblas-srpm-macros noarch 0:2-23.fc46 fedora 124.0 B openldap x86_64 0:2.6.15-1.fc46 fedora 683.4 KiB openssl-libs x86_64 1:4.0.3-1.fc46 fedora 6.7 MiB p11-kit x86_64 0:0.26.5-1.fc45 fedora 2.6 MiB p11-kit-trust x86_64 0:0.26.5-1.fc45 fedora 478.4 KiB package-notes-srpm-macros noarch 0:0.20-2.fc45 fedora 1.6 KiB pam-libs x86_64 0:1.7.2-4.fc45 fedora 134.5 KiB pcre2 x86_64 0:10.47-1.fc45.2 fedora 718.5 KiB pcre2-syntax noarch 0:10.47-1.fc45.2 fedora 281.9 KiB perl-srpm-macros noarch 0:1-65.fc45 fedora 861.0 B pkgconf x86_64 0:2.5.1-2.fc45 fedora 92.7 KiB pkgconf-m4 noarch 0:2.5.1-2.fc45 fedora 14.3 KiB pkgconf-pkg-config x86_64 0:2.5.1-2.fc45 fedora 989.0 B policycoreutils x86_64 0:3.11-2.fc45 fedora 892.9 KiB popt x86_64 0:1.19-11.fc45 fedora 136.7 KiB publicsuffix-list-dafsa noarch 0:20260624-2.fc45 fedora 71.3 KiB pyproject-srpm-macros noarch 0:1.24.0-1.fc46 fedora 3.4 KiB python-srpm-macros noarch 0:3.15-2.fc45 fedora 51.6 KiB qt5-srpm-macros noarch 0:5.15.18-3.fc45 fedora 500.0 B qt6-srpm-macros noarch 0:6.11.2-1.fc46 fedora 472.0 B readline x86_64 0:8.3-7.fc46 fedora 515.6 KiB redhat-systemd-presets noarch 0:102-3.fc45 fedora 1.0 KiB redhat-systemd-presets-common noarch 0:102-3.fc45 fedora 16.9 KiB rpm x86_64 0:6.1.0-1.fc46 fedora 3.1 MiB rpm-build-libs x86_64 0:6.1.0-1.fc46 fedora 288.3 KiB rpm-libs x86_64 0:6.1.0-1.fc46 fedora 1.1 MiB rpm-plugin-selinux x86_64 0:6.1.0-1.fc46 fedora 11.9 KiB rpm-sequoia x86_64 0:1.10.3-1.fc46 fedora 2.4 MiB rpm-sign-libs x86_64 0:6.1.0-1.fc46 fedora 39.6 KiB rust-srpm-macros noarch 0:28.5-2.fc45 fedora 5.5 KiB selinux-policy noarch 0:45.21-1.fc46 fedora 32.1 KiB selinux-policy-targeted noarch 0:45.21-1.fc46 fedora 19.0 MiB setup noarch 0:2.15.1-2.fc45 fedora 725.6 KiB sqlite-libs x86_64 0:3.53.4-1.fc45 fedora 1.6 MiB systemd-libs x86_64 0:262-3.fc46 fedora 2.8 MiB systemd-standalone-sysusers x86_64 0:262-3.fc46 fedora 981.3 KiB tpm2-tss x86_64 0:4.2.0-1.fc45 fedora 1.7 MiB tree-sitter-srpm-macros noarch 0:0.4.6-2.fc45 fedora 8.6 KiB util-linux-core x86_64 0:2.42.4-2.fc46 fedora 1.5 MiB xxhash-libs x86_64 0:0.8.4-1.fc46 fedora 94.0 KiB xz-libs x86_64 1:5.8.4-1.fc46 fedora 221.7 KiB zig-srpm-macros noarch 0:1-9.fc45 fedora 1.3 KiB zip x86_64 0:3.0-46.fc45 fedora 694.1 KiB zlib-ng-compat x86_64 0:2.3.3-6.fc45 fedora 165.6 KiB zstd x86_64 0:1.5.7-6.fc45 fedora 502.6 KiB Installing groups: Buildsystem building group Transaction Summary: Installing: 190 packages Total size of inbound packages is 72 MiB. Need to download 0 B. After this operation, 230 MiB extra will be used (install 230 MiB, remove 0 B). [ 1/190] tar-2:1.35-9.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 2/190] bzip2-0:1.0.8-24.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 3/190] redhat-rpm-config-0:345-4.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 4/190] rpm-build-0:6.1.0-1.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 5/190] unzip-0:6.0-71.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 6/190] cpio-0:2.15-10.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 7/190] which-0:2.25-2.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 8/190] bash-0:5.3.20-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 9/190] coreutils-0:9.12-1.fc46.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 10/190] grep-0:3.12-4.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 11/190] patch-0:2.8-6.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 12/190] sed-0:4.10-2.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 13/190] shadow-utils-2:4.20.0-1.fc45. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 14/190] diffutils-0:3.12-6.fc45.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 15/190] fedora-release-common-0:46-0. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 16/190] findutils-1:4.11.0-2.fc45.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 17/190] glibc-minimal-langpack-0:2.44 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 18/190] gzip-0:1.15-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 19/190] info-0:7.3-3.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 20/190] xz-1:5.8.4-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 21/190] util-linux-0:2.42.4-2.fc46.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 22/190] gawk-0:5.4.1-1.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 23/190] glibc-0:2.44.9000-5.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 24/190] libacl-0:2.4.0-2.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 25/190] libselinux-0:3.11-5.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 26/190] bzip2-libs-0:1.0.8-24.fc45.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 27/190] R-srpm-macros-0:1.3.7-3.fc45. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 28/190] ansible-srpm-macros-0:1-22.fc 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 29/190] build-reproducibility-srpm-ma 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 30/190] cmake-srpm-macros-0:4.3.0-5.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 31/190] dwz-0:0.17-3.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 32/190] efi-srpm-macros-0:6-9.fc45.no 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 33/190] erlang-srpm-macros-0:0.4.0-1. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 34/190] file-0:5.48-3.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 35/190] filesystem-srpm-macros-0:3.18 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 36/190] fonts-srpm-macros-1:5.0.0-4.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 37/190] forge-srpm-macros-0:0.4.0-5.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 38/190] fpc-srpm-macros-0:1.3-17.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 39/190] gap-srpm-macros-0:2-3.fc45.no 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 40/190] ghc-srpm-macros-0:1.10-2.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 41/190] gnat-srpm-macros-0:7-3.fc45.n 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 42/190] gnome-srpm-macros-0:1.0-2.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 43/190] go-srpm-macros-0:3.8.0-3.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 44/190] java-srpm-macros-0:1-9.fc45.n 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 45/190] kernel-srpm-macros-0:1.0-30.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 46/190] lua-srpm-macros-0:1-18.fc45.n 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 47/190] meson-srpm-macros-0:1.12.1-2. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 48/190] ocaml-srpm-macros-0:11-4.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 49/190] openblas-srpm-macros-0:2-23.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 50/190] package-notes-srpm-macros-0:0 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 51/190] perl-srpm-macros-0:1-65.fc45. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 52/190] pyproject-srpm-macros-0:1.24. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 53/190] python-srpm-macros-0:3.15-2.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 54/190] qt5-srpm-macros-0:5.15.18-3.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 55/190] qt6-srpm-macros-0:6.11.2-1.fc 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 56/190] rpm-0:6.1.0-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 57/190] rust-srpm-macros-0:28.5-2.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 58/190] tree-sitter-srpm-macros-0:0.4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 59/190] zig-srpm-macros-0:1-9.fc45.no 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 60/190] zip-0:3.0-46.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 61/190] debugedit-0:5.3-3.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 62/190] elfutils-0:0.196-1.fc46.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 63/190] elfutils-libelf-0:0.196-1.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 64/190] libarchive-0:3.8.9-2.fc46.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 65/190] libgcc-0:16.2.1-2.fc46.1.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 66/190] libstdc++-0:16.2.1-2.fc46.1.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 67/190] popt-0:1.19-11.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 68/190] readline-0:8.3-7.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 69/190] rpm-build-libs-0:6.1.0-1.fc46 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 70/190] rpm-libs-0:6.1.0-1.fc46.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 71/190] zstd-0:1.5.7-6.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 72/190] filesystem-0:3.18-59.fc45.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 73/190] ncurses-libs-0:6.6-3.fc45.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 74/190] coreutils-common-0:9.12-1.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 75/190] gmp-1:6.3.0-6.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 76/190] libattr-0:2.6.0-2.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 77/190] libcap-0:2.78-2.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 78/190] openssl-libs-1:4.0.3-1.fc46.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 79/190] systemd-libs-0:262-3.fc46.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 80/190] pcre2-0:10.47-1.fc45.2.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 81/190] ed-0:1.22.6-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 82/190] audit-libs-0:4.2.1-2.fc45.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 83/190] libeconf-0:0.7.9-4.fc45.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 84/190] libsemanage-0:3.11-4.fc46.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 85/190] libxcrypt-0:4.5.2-4.fc45.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 86/190] pam-libs-0:1.7.2-4.fc45.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 87/190] setup-0:2.15.1-2.fc45.noarch 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 88/190] fedora-repos-0:46-0.3.noarch 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 89/190] redhat-systemd-presets-0:102- 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 90/190] glibc-common-0:2.44.9000-5.fc 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 91/190] xz-libs-1:5.8.4-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 92/190] libblkid-0:2.42.4-2.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 93/190] libcap-ng-0:0.9.6-1.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 94/190] libfdisk-0:2.42.4-2.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 95/190] liblastlog2-0:2.42.4-2.fc46.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 96/190] libmount-0:2.42.4-2.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 97/190] libsmartcols-0:2.42.4-2.fc46. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 98/190] libuuid-0:2.42.4-2.fc46.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 99/190] util-linux-core-0:2.42.4-2.fc 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [100/190] zlib-ng-compat-0:2.3.3-6.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [101/190] mpfr-0:4.2.2-4.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [102/190] glibc-gconv-extra-0:2.44.9000 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [103/190] libsepol-0:3.11-2.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [104/190] add-determinism-0:0.7.3-3.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [105/190] linkdupes-0:0.7.3-3.fc45.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [106/190] file-libs-0:5.48-3.fc46.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [107/190] curl-0:8.23.0~rc3-1.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [108/190] elfutils-libs-0:0.196-1.fc46. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [109/190] elfutils-debuginfod-client-0: 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [110/190] json-c-0:0.18-9.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [111/190] libpfm-0:4.13.0-23.fc45.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [112/190] libzstd-0:1.5.7-6.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [113/190] libxml2-0:2.15.4-1.fc46.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [114/190] lz4-libs-0:1.10.0-5.fc45.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [115/190] libgomp-0:16.2.1-2.fc46.1.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [116/190] lua-libs-0:5.5.1-2.fc46.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [117/190] rpm-sign-libs-0:6.1.0-1.fc46. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [118/190] rpm-sequoia-0:1.10.3-1.fc46.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [119/190] sqlite-libs-0:3.53.4-1.fc45.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [120/190] ncurses-base-0:6.6-3.fc45.noa 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [121/190] gnulib-l10n-0:20241231-4.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [122/190] ca-certificates-0:2026.2.90_v 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [123/190] crypto-policies-0:20260713-2. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [124/190] fips-provider-0:1.5.3-1.fc46. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [125/190] pcre2-syntax-0:10.47-1.fc45.2 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [126/190] fedora-gpg-keys-0:46-0.3.noar 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [127/190] fedora-repos-rawhide-0:46-0.3 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [128/190] redhat-systemd-presets-common 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [129/190] gnupg2-0:2.4.9-18.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [130/190] ima-evm-utils-libs-0:1.6.2-12 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [131/190] libfsverity-0:1.7-4.fc45.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [132/190] gpgverify-0:2.2-5.fc45.noarch 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [133/190] gnupg2-dirmngr-0:2.4.9-18.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [134/190] gnupg2-gpg-agent-0:2.4.9-18.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [135/190] gnupg2-gpgconf-0:2.4.9-18.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [136/190] gnupg2-keyboxd-0:2.4.9-18.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [137/190] gnupg2-verify-0:2.4.9-18.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [138/190] libassuan-0:2.5.7-6.fc45.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [139/190] libgcrypt-0:1.12.4-1.fc46.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [140/190] libgpg-error-0:1.61-2.fc45.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [141/190] npth-0:1.8-5.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [142/190] tpm2-tss-0:4.2.0-1.fc45.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [143/190] gnutls-0:3.8.13-5.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [144/190] libksba-0:1.8.1-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [145/190] openldap-0:2.6.15-1.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [146/190] libusb1-0:1.0.30-2.fc45.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [147/190] libidn2-0:2.3.8-4.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [148/190] libtasn1-0:4.21.0-2.fc45.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [149/190] libunistring-0:1.1-12.fc45.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [150/190] nettle-0:4.0-5.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [151/190] p11-kit-0:0.26.5-1.fc45.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [152/190] cyrus-sasl-lib-0:2.1.28-37.fc 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [153/190] libevent-0:2.1.13-1.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [154/190] libtool-ltdl-0:2.6.2-1.fc46.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [155/190] libffi-0:3.8.0-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [156/190] gdbm-libs-1:1.26-1.fc46.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [157/190] binutils-0:2.47.50-15.fc46.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [158/190] alternatives-0:1.33-6.fc45.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [159/190] jansson-0:2.14-5.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [160/190] pkgconf-pkg-config-0:2.5.1-2. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [161/190] pkgconf-0:2.5.1-2.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [162/190] pkgconf-m4-0:2.5.1-2.fc45.noa 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [163/190] libpkgconf-0:2.5.1-2.fc45.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [164/190] p11-kit-trust-0:0.26.5-1.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [165/190] fedora-release-0:46-0.1.noarc 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [166/190] systemd-standalone-sysusers-0 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [167/190] gdb-minimal-0:17.2-6.fc46.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [168/190] xxhash-libs-0:0.8.4-1.fc46.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [169/190] fedora-release-identity-basic 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [170/190] libcurl-0:8.23.0~rc3-1.fc46.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [171/190] krb5-libs-0:1.22.2-9.fc45.x86 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [172/190] libbrotli-0:1.2.0-6.fc45.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [173/190] libnghttp2-0:1.69.0-6.fc46.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [174/190] libnghttp3-0:1.18.0-1.fc45.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [175/190] libpsl-0:0.23.3-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [176/190] libssh-0:0.12.2-1.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [177/190] ngtcp2-0:1.22.1-3.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [178/190] ngtcp2-crypto-ossl-0:1.22.1-3 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [179/190] keyutils-libs-0:1.6.3-8.fc45. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [180/190] libcom_err-0:1.47.4-2.fc45.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [181/190] libverto-0:0.3.2-13.fc45.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [182/190] publicsuffix-list-dafsa-0:202 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [183/190] libfido2-0:1.17.0-6.fc46.x86_ 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [184/190] libssh-config-0:0.12.2-1.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [185/190] libcbor-0:0.14.0-3.fc45.x86_6 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [186/190] selinux-policy-targeted-0:45. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [187/190] policycoreutils-0:3.11-2.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [188/190] selinux-policy-0:45.21-1.fc46 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [189/190] libselinux-utils-0:3.11-5.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [190/190] rpm-plugin-selinux-0:6.1.0-1. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded -------------------------------------------------------------------------------- [190/190] Total 100% | 0.0 B/s | 0.0 B | 00m00s Running transaction Importing OpenPGP key 0x91211FCE: UserID : "Fedora (46) " Fingerprint: D924B10D3E810DABDD8B56B596E7E91491211FCE From : file:///usr/share/distribution-gpg-keys/fedora/RPM-GPG-KEY-fedora-46-primary The key was successfully imported. Importing OpenPGP key 0x91211FCE: UserID : "Fedora (46) " Fingerprint: D924B10D3E810DABDD8B56B596E7E91491211FCE From : file:///usr/share/distribution-gpg-keys/fedora/RPM-GPG-KEY-fedora-46-primary The key was successfully imported. Importing OpenPGP key 0xF577861E: UserID : "Fedora (45) " Fingerprint: 4F50A6114CD5C6976A7F1179655A4B02F577861E From : file:///usr/share/distribution-gpg-keys/fedora/RPM-GPG-KEY-fedora-45-primary The key was successfully imported. Importing OpenPGP key 0x9488FB64: UserID : "Fedora (47) " Fingerprint: B2E766FA50CA6FA2D5ED06FC09D879E09488FB64 From : file:///usr/share/distribution-gpg-keys/fedora/RPM-GPG-KEY-fedora-47-primary The key was successfully imported. [ 1/192] Verify package files 100% | 727.0 B/s | 190.0 B | 00m00s >>> Running %pretrans scriptlet: filesystem-0:3.18-59.fc45.x86_64 >>> Finished %pretrans scriptlet: filesystem-0:3.18-59.fc45.x86_64 >>> [RPM] failed to open /var/lib/mock/fedora-rawhide-x86_64-1791974115.829543/root/etc/group for id/name lookup: No such file or directory [ 2/192] Prepare transaction 100% | 3.5 KiB/s | 190.0 B | 00m00s [ 3/192] Installing libgcc-0:16.2.1-2. 100% | 266.0 MiB/s | 272.4 KiB | 00m00s [ 4/192] Installing redhat-systemd-pre 100% | 0.0 B/s | 1.5 KiB | 00m00s [ 5/192] Installing redhat-systemd-pre 100% | 0.0 B/s | 18.1 KiB | 00m00s [ 6/192] Installing libssh-config-0:0. 100% | 0.0 B/s | 816.0 B | 00m00s [ 7/192] Installing publicsuffix-list- 100% | 0.0 B/s | 72.0 KiB | 00m00s [ 8/192] Installing fedora-release-ide 100% | 0.0 B/s | 920.0 B | 00m00s [ 9/192] Installing fedora-repos-rawhi 100% | 0.0 B/s | 2.5 KiB | 00m00s [ 10/192] Installing fedora-gpg-keys-0: 100% | 44.4 MiB/s | 181.7 KiB | 00m00s [ 11/192] Installing fedora-repos-0:46- 100% | 0.0 B/s | 5.9 KiB | 00m00s [ 12/192] Installing fedora-release-com 100% | 0.0 B/s | 8.0 KiB | 00m00s [ 13/192] Installing fedora-release-0:4 100% | 17.3 KiB/s | 124.0 B | 00m00s >>> Running sysusers scriptlet: setup-0:2.15.1-2.fc45.noarch >>> Finished sysusers scriptlet: setup-0:2.15.1-2.fc45.noarch >>> Scriptlet output: >>> Creating group 'adm' with GID 4. >>> Creating group 'audio' with GID 63. >>> Creating group 'cdrom' with GID 11. >>> Creating group 'clock' with GID 103. >>> Creating group 'dialout' with GID 18. >>> Creating group 'disk' with GID 6. >>> Creating group 'floppy' with GID 19. >>> Creating group 'ftp' with GID 50. >>> Creating group 'games' with GID 20. >>> Creating group 'input' with GID 104. >>> Creating group 'kmem' with GID 9. >>> Creating group 'kvm' with GID 36. >>> Creating group 'lock' with GID 54. >>> Creating group 'lp' with GID 7. >>> Creating group 'mail' with GID 12. >>> Creating group 'man' with GID 15. >>> Creating group 'mem' with GID 8. >>> Creating group 'nobody' with GID 65534. >>> Creating group 'render' with GID 105. >>> Creating group 'root' with GID 0. >>> Creating group 'sgx' with GID 106. >>> Creating group 'sys' with GID 3. >>> Creating group 'tape' with GID 33. >>> Creating group 'tty' with GID 5. >>> Creating group 'users' with GID 100. >>> Creating group 'utmp' with GID 22. >>> Creating group 'video' with GID 39. >>> Creating group 'wheel' with GID 10. >>> Creating user 'adm' (adm) with UID 3 and GID 4. >>> Creating group 'bin' with GID 1. >>> Creating user 'bin' (bin) with UID 1 and GID 1. >>> Creating group 'daemon' with GID 2. >>> Creating user 'daemon' (daemon) with UID 2 and GID 2. >>> Creating user 'ftp' (FTP User) with UID 14 and GID 50. >>> Creating user 'games' (games) with UID 12 and GID 100. >>> Creating user 'halt' (halt) with UID 7 and GID 0. >>> Creating user 'lp' (lp) with UID 4 and GID 7. >>> Creating user 'mail' (mail) with UID 8 and GID 12. >>> Creating user 'nobody' (Kernel Overflow User) with UID 65534 and GID 65534. >>> Creating user 'operator' (operator) with UID 11 and GID 0. >>> Creating user 'root' (Super User) with UID 0 and GID 0. >>> Creating user 'shutdown' (shutdown) with UID 6 and GID 0. >>> Creating user 'sync' (sync) with UID 5 and GID 0. >>> [ 14/192] Installing setup-0:2.15.1-2.f 100% | 42.0 MiB/s | 731.3 KiB | 00m00s >>> [RPM] /etc/hosts created as /etc/hosts.rpmnew [ 15/192] Installing filesystem-0:3.18- 100% | 2.7 MiB/s | 253.6 KiB | 00m00s [ 16/192] Installing pkgconf-m4-0:2.5.1 100% | 0.0 B/s | 14.7 KiB | 00m00s [ 17/192] Installing pcre2-syntax-0:10. 100% | 277.7 MiB/s | 284.3 KiB | 00m00s [ 18/192] Installing gnulib-l10n-0:2024 100% | 215.5 MiB/s | 661.9 KiB | 00m00s [ 19/192] Installing coreutils-common-0 100% | 412.9 MiB/s | 11.6 MiB | 00m00s [ 20/192] Installing ncurses-base-0:6.6 100% | 86.7 MiB/s | 355.3 KiB | 00m00s [ 21/192] Installing bash-0:5.3.20-1.fc 100% | 249.2 MiB/s | 8.5 MiB | 00m00s [ 22/192] Installing glibc-common-0:2.4 100% | 51.8 MiB/s | 1.0 MiB | 00m00s [ 23/192] Installing glibc-gconv-extra- 100% | 324.5 MiB/s | 7.8 MiB | 00m00s [ 24/192] Installing glibc-0:2.44.9000- 100% | 188.9 MiB/s | 7.2 MiB | 00m00s [ 25/192] Installing ncurses-libs-0:6.6 100% | 238.0 MiB/s | 974.9 KiB | 00m00s [ 26/192] Installing glibc-minimal-lang 100% | 0.0 B/s | 124.0 B | 00m00s [ 27/192] Installing zlib-ng-compat-0:2 100% | 162.5 MiB/s | 166.4 KiB | 00m00s [ 28/192] Installing bzip2-libs-0:1.0.8 100% | 0.0 B/s | 81.6 KiB | 00m00s [ 29/192] Installing libgpg-error-0:1.6 100% | 52.1 MiB/s | 959.7 KiB | 00m00s [ 30/192] Installing readline-0:8.3-7.f 100% | 252.8 MiB/s | 517.7 KiB | 00m00s [ 31/192] Installing libstdc++-0:16.2.1 100% | 440.9 MiB/s | 3.1 MiB | 00m00s [ 32/192] Installing libzstd-0:1.5.7-6. 100% | 467.5 MiB/s | 957.4 KiB | 00m00s [ 33/192] Installing elfutils-libelf-0: 100% | 481.0 MiB/s | 1.4 MiB | 00m00s [ 34/192] Installing libassuan-0:2.5.7- 100% | 161.8 MiB/s | 165.7 KiB | 00m00s [ 35/192] Installing libgcrypt-0:1.12.4 100% | 416.6 MiB/s | 1.7 MiB | 00m00s [ 36/192] Installing libacl-0:2.4.0-2.f 100% | 0.0 B/s | 44.7 KiB | 00m00s [ 37/192] Installing gmp-1:6.3.0-6.fc45 100% | 399.1 MiB/s | 817.4 KiB | 00m00s [ 38/192] Installing systemd-libs-0:262 100% | 395.7 MiB/s | 2.8 MiB | 00m00s [ 39/192] Installing libuuid-0:2.42.4-2 100% | 0.0 B/s | 38.2 KiB | 00m00s [ 40/192] Installing popt-0:1.19-11.fc4 100% | 70.0 MiB/s | 143.3 KiB | 00m00s [ 41/192] Installing xz-libs-1:5.8.4-1. 100% | 217.6 MiB/s | 222.8 KiB | 00m00s [ 42/192] Installing sqlite-libs-0:3.53 100% | 404.7 MiB/s | 1.6 MiB | 00m00s [ 43/192] Installing npth-0:1.8-5.fc45. 100% | 0.0 B/s | 50.6 KiB | 00m00s [ 44/192] Installing elfutils-libs-0:0. 100% | 352.2 MiB/s | 721.3 KiB | 00m00s [ 45/192] Installing libblkid-0:2.42.4- 100% | 276.6 MiB/s | 283.3 KiB | 00m00s [ 46/192] Installing libsepol-0:3.11-2. 100% | 423.4 MiB/s | 867.1 KiB | 00m00s [ 47/192] Installing gnupg2-gpgconf-0:2 100% | 15.6 MiB/s | 255.9 KiB | 00m00s [ 48/192] Installing pcre2-0:10.47-1.fc 100% | 351.5 MiB/s | 720.0 KiB | 00m00s [ 49/192] Installing libselinux-0:3.11- 100% | 201.6 MiB/s | 206.4 KiB | 00m00s [ 50/192] Installing grep-0:3.12-4.fc45 100% | 52.8 MiB/s | 1.0 MiB | 00m00s [ 51/192] Installing sed-0:4.10-2.fc45. 100% | 47.5 MiB/s | 874.9 KiB | 00m00s [ 52/192] Installing findutils-1:4.11.0 100% | 97.9 MiB/s | 2.0 MiB | 00m00s [ 53/192] Installing libxcrypt-0:4.5.2- 100% | 289.0 MiB/s | 295.9 KiB | 00m00s [ 54/192] Installing json-c-0:0.18-9.fc 100% | 0.0 B/s | 83.9 KiB | 00m00s [ 55/192] Installing libtasn1-0:4.21.0- 100% | 174.3 MiB/s | 178.5 KiB | 00m00s [ 56/192] Installing libunistring-0:1.1 100% | 433.6 MiB/s | 1.7 MiB | 00m00s [ 57/192] Installing libidn2-0:2.3.8-4. 100% | 61.0 MiB/s | 562.6 KiB | 00m00s [ 58/192] Installing crypto-policies-0: 100% | 38.9 MiB/s | 159.5 KiB | 00m00s [ 59/192] Installing xz-1:5.8.4-1.fc46. 100% | 67.9 MiB/s | 1.4 MiB | 00m00s [ 60/192] Installing libmount-0:2.42.4- 100% | 400.4 MiB/s | 410.0 KiB | 00m00s [ 61/192] Installing gnupg2-verify-0:2. 100% | 21.8 MiB/s | 357.7 KiB | 00m00s [ 62/192] Installing mpfr-0:4.2.2-4.fc4 100% | 277.0 MiB/s | 850.9 KiB | 00m00s [ 63/192] Installing gawk-0:5.4.1-1.fc4 100% | 106.1 MiB/s | 2.2 MiB | 00m00s [ 64/192] Installing dwz-0:0.17-3.fc45. 100% | 17.9 MiB/s | 292.5 KiB | 00m00s [ 65/192] Installing libksba-0:1.8.1-1. 100% | 212.1 MiB/s | 434.4 KiB | 00m00s [ 66/192] Installing unzip-0:6.0-71.fc4 100% | 25.6 MiB/s | 445.3 KiB | 00m00s [ 67/192] Installing file-libs-0:5.48-3 100% | 726.1 MiB/s | 12.3 MiB | 00m00s [ 68/192] Installing file-0:5.48-3.fc46 100% | 6.3 MiB/s | 103.4 KiB | 00m00s [ 69/192] Installing diffutils-0:3.12-6 100% | 82.4 MiB/s | 1.6 MiB | 00m00s [ 70/192] Installing libattr-0:2.6.0-2. 100% | 0.0 B/s | 25.2 KiB | 00m00s [ 71/192] Installing libeconf-0:0.7.9-4 100% | 0.0 B/s | 66.4 KiB | 00m00s [ 72/192] Installing libcap-ng-0:0.9.6- 100% | 0.0 B/s | 70.6 KiB | 00m00s [ 73/192] Installing audit-libs-0:4.2.1 100% | 383.9 MiB/s | 393.1 KiB | 00m00s [ 74/192] Installing pam-libs-0:1.7.2-4 100% | 133.7 MiB/s | 136.9 KiB | 00m00s [ 75/192] Installing libcap-0:2.78-2.fc 100% | 13.0 MiB/s | 213.3 KiB | 00m00s [ 76/192] Installing libsemanage-0:3.11 100% | 314.8 MiB/s | 322.4 KiB | 00m00s [ 77/192] Installing libsmartcols-0:2.4 100% | 185.2 MiB/s | 189.6 KiB | 00m00s [ 78/192] Installing lua-libs-0:5.5.1-2 100% | 292.4 MiB/s | 299.4 KiB | 00m00s [ 79/192] Installing libffi-0:3.8.0-1.f 100% | 94.6 MiB/s | 96.9 KiB | 00m00s [ 80/192] Installing p11-kit-0:0.26.5-1 100% | 114.6 MiB/s | 2.6 MiB | 00m00s [ 81/192] Installing alternatives-0:1.3 100% | 3.9 MiB/s | 63.6 KiB | 00m00s [ 82/192] Installing p11-kit-trust-0:0. 100% | 20.4 MiB/s | 480.1 KiB | 00m00s [ 83/192] Installing ngtcp2-0:1.22.1-3. 100% | 164.0 MiB/s | 335.8 KiB | 00m00s [ 84/192] Installing util-linux-core-0: 100% | 72.0 MiB/s | 1.5 MiB | 00m00s [ 85/192] Installing liblastlog2-0:2.42 100% | 7.8 MiB/s | 39.8 KiB | 00m00s [ 86/192] Installing zip-0:3.0-46.fc45. 100% | 35.9 MiB/s | 698.0 KiB | 00m00s [ 87/192] Installing gnupg2-keyboxd-0:2 100% | 39.6 MiB/s | 202.5 KiB | 00m00s [ 88/192] Installing libpsl-0:0.23.3-1. 100% | 79.6 MiB/s | 81.5 KiB | 00m00s [ 89/192] Installing tar-2:1.35-9.fc45. 100% | 123.9 MiB/s | 3.0 MiB | 00m00s [ 90/192] Installing linkdupes-0:0.7.3- 100% | 42.5 MiB/s | 783.5 KiB | 00m00s [ 91/192] Installing libselinux-utils-0 100% | 18.4 MiB/s | 320.4 KiB | 00m00s [ 92/192] Installing libfdisk-0:2.42.4- 100% | 384.0 MiB/s | 393.2 KiB | 00m00s [ 93/192] Installing fips-provider-0:1. 100% | 439.0 MiB/s | 4.8 MiB | 00m00s [ 94/192] Installing openssl-libs-1:4.0 100% | 418.7 MiB/s | 6.7 MiB | 00m00s [ 95/192] Installing coreutils-0:9.12-1 100% | 176.5 MiB/s | 6.4 MiB | 00m00s [ 96/192] Installing ca-certificates-0: 100% | 2.4 MiB/s | 2.5 MiB | 00m01s [ 97/192] Installing gzip-0:1.15-1.fc46 100% | 23.2 MiB/s | 450.7 KiB | 00m00s [ 98/192] Installing util-linux-0:2.42. 100% | 98.9 MiB/s | 3.8 MiB | 00m00s [ 99/192] Installing policycoreutils-0: 100% | 33.3 MiB/s | 921.4 KiB | 00m00s [100/192] Installing selinux-policy-0:4 100% | 2.0 MiB/s | 34.5 KiB | 00m00s [101/192] Installing selinux-policy-tar 100% | 226.1 MiB/s | 15.2 MiB | 00m00s [102/192] Installing rpm-sequoia-0:1.10 100% | 349.6 MiB/s | 2.4 MiB | 00m00s [103/192] Installing libfsverity-0:1.7- 100% | 0.0 B/s | 25.4 KiB | 00m00s [104/192] Installing libevent-0:2.1.13- 100% | 320.5 MiB/s | 984.5 KiB | 00m00s [105/192] Installing ngtcp2-crypto-ossl 100% | 0.0 B/s | 52.5 KiB | 00m00s [106/192] Installing libusb1-0:1.0.30-2 100% | 16.1 MiB/s | 181.8 KiB | 00m00s >>> Running sysusers scriptlet: tpm2-tss-0:4.2.0-1.fc45.x86_64 >>> Finished sysusers scriptlet: tpm2-tss-0:4.2.0-1.fc45.x86_64 >>> Scriptlet output: >>> Creating group 'tss' with GID 59. >>> Creating user 'tss' (Account used for TPM access) with UID 59 and GID 59. >>> [107/192] Installing tpm2-tss-0:4.2.0-1 100% | 333.5 MiB/s | 1.7 MiB | 00m00s [108/192] Installing ima-evm-utils-libs 100% | 56.5 MiB/s | 57.9 KiB | 00m00s [109/192] Installing gnupg2-gpg-agent-0 100% | 27.8 MiB/s | 682.8 KiB | 00m00s [110/192] Installing nettle-0:4.0-5.fc4 100% | 262.0 MiB/s | 805.0 KiB | 00m00s [111/192] Installing gnutls-0:3.8.13-5. 100% | 383.7 MiB/s | 3.8 MiB | 00m00s [112/192] Installing zstd-0:1.5.7-6.fc4 100% | 29.1 MiB/s | 506.1 KiB | 00m00s [113/192] Installing libxml2-0:2.15.4-1 100% | 82.7 MiB/s | 1.7 MiB | 00m00s [114/192] Installing bzip2-0:1.0.8-24.f 100% | 6.1 MiB/s | 99.5 KiB | 00m00s [115/192] Installing add-determinism-0: 100% | 107.9 MiB/s | 2.2 MiB | 00m00s [116/192] Installing build-reproducibil 100% | 0.0 B/s | 1.5 KiB | 00m00s [117/192] Installing cpio-0:2.15-10.fc4 100% | 58.1 MiB/s | 1.1 MiB | 00m00s [118/192] Installing ed-0:1.22.6-1.fc46 100% | 9.3 MiB/s | 153.2 KiB | 00m00s [119/192] Installing patch-0:2.8-6.fc46 100% | 13.9 MiB/s | 228.1 KiB | 00m00s [120/192] Installing libpfm-0:4.13.0-23 100% | 576.1 MiB/s | 1.7 MiB | 00m00s [121/192] Installing lz4-libs-0:1.10.0- 100% | 162.5 MiB/s | 166.4 KiB | 00m00s [122/192] Installing libarchive-0:3.8.9 100% | 327.4 MiB/s | 1.0 MiB | 00m00s [123/192] Installing libgomp-0:16.2.1-2 100% | 282.7 MiB/s | 578.9 KiB | 00m00s [124/192] Installing libtool-ltdl-0:2.6 100% | 0.0 B/s | 71.1 KiB | 00m00s [125/192] Installing gdbm-libs-1:1.26-1 100% | 132.7 MiB/s | 135.9 KiB | 00m00s [126/192] Installing cyrus-sasl-lib-0:2 100% | 111.4 MiB/s | 2.3 MiB | 00m00s [127/192] Installing openldap-0:2.6.15- 100% | 335.6 MiB/s | 687.2 KiB | 00m00s [128/192] Installing gnupg2-dirmngr-0:2 100% | 26.9 MiB/s | 632.8 KiB | 00m00s [129/192] Installing gnupg2-0:2.4.9-18. 100% | 209.7 MiB/s | 6.5 MiB | 00m00s [130/192] Installing gpgverify-0:2.2-5. 100% | 0.0 B/s | 9.4 KiB | 00m00s [131/192] Installing jansson-0:2.14-5.f 100% | 88.2 MiB/s | 90.3 KiB | 00m00s [132/192] Installing libpkgconf-0:2.5.1 100% | 89.1 MiB/s | 91.3 KiB | 00m00s [133/192] Installing pkgconf-0:2.5.1-2. 100% | 5.8 MiB/s | 95.2 KiB | 00m00s [134/192] Installing pkgconf-pkg-config 100% | 118.2 KiB/s | 1.8 KiB | 00m00s [135/192] Installing systemd-standalone 100% | 53.3 MiB/s | 981.8 KiB | 00m00s [136/192] Installing rpm-libs-0:6.1.0-1 100% | 366.4 MiB/s | 1.1 MiB | 00m00s [137/192] Installing rpm-sign-libs-0:6. 100% | 0.0 B/s | 40.5 KiB | 00m00s [138/192] Installing rpm-build-libs-0:6 100% | 282.4 MiB/s | 289.2 KiB | 00m00s [139/192] Installing xxhash-libs-0:0.8. 100% | 93.1 MiB/s | 95.4 KiB | 00m00s [140/192] Installing libbrotli-0:1.2.0- 100% | 282.3 MiB/s | 867.3 KiB | 00m00s [141/192] Installing libnghttp2-0:1.69. 100% | 163.3 MiB/s | 167.3 KiB | 00m00s [142/192] Installing libnghttp3-0:1.18. 100% | 161.0 MiB/s | 164.8 KiB | 00m00s [143/192] Installing keyutils-libs-0:1. 100% | 0.0 B/s | 55.6 KiB | 00m00s [144/192] Installing libcom_err-0:1.47. 100% | 0.0 B/s | 64.1 KiB | 00m00s [145/192] Installing libverto-0:0.3.2-1 100% | 26.4 MiB/s | 27.1 KiB | 00m00s [146/192] Installing krb5-libs-0:1.22.2 100% | 341.0 MiB/s | 2.4 MiB | 00m00s [147/192] Installing libcbor-0:0.14.0-3 100% | 0.0 B/s | 84.9 KiB | 00m00s [148/192] Installing libfido2-0:1.17.0- 100% | 252.0 MiB/s | 258.1 KiB | 00m00s [149/192] Installing libssh-0:0.12.2-1. 100% | 355.4 MiB/s | 727.8 KiB | 00m00s [150/192] Installing libcurl-0:8.23.0~r 100% | 360.6 MiB/s | 1.1 MiB | 00m00s [151/192] Installing elfutils-debuginfo 100% | 5.0 MiB/s | 82.2 KiB | 00m00s [152/192] Installing elfutils-0:0.196-1 100% | 138.1 MiB/s | 3.2 MiB | 00m00s [153/192] Installing binutils-0:2.47.50 100% | 318.4 MiB/s | 24.5 MiB | 00m00s [154/192] Installing gdb-minimal-0:17.2 100% | 283.3 MiB/s | 14.2 MiB | 00m00s [155/192] Installing debugedit-0:5.3-3. 100% | 12.9 MiB/s | 224.1 KiB | 00m00s [156/192] Installing curl-0:8.23.0~rc3- 100% | 19.1 MiB/s | 488.7 KiB | 00m00s [157/192] Installing rpm-0:6.1.0-1.fc46 100% | 75.9 MiB/s | 2.5 MiB | 00m00s [158/192] Installing cmake-srpm-macros- 100% | 0.0 B/s | 804.0 B | 00m00s [159/192] Installing efi-srpm-macros-0: 100% | 0.0 B/s | 41.3 KiB | 00m00s [160/192] Installing java-srpm-macros-0 100% | 224.2 KiB/s | 1.1 KiB | 00m00s [161/192] Installing lua-srpm-macros-0: 100% | 0.0 B/s | 1.9 KiB | 00m00s [162/192] Installing tree-sitter-srpm-m 100% | 0.0 B/s | 9.6 KiB | 00m00s [163/192] Installing zig-srpm-macros-0: 100% | 0.0 B/s | 1.9 KiB | 00m00s [164/192] Installing filesystem-srpm-ma 100% | 0.0 B/s | 38.9 KiB | 00m00s [165/192] Installing rust-srpm-macros-0 100% | 0.0 B/s | 6.4 KiB | 00m00s [166/192] Installing qt6-srpm-macros-0: 100% | 0.0 B/s | 748.0 B | 00m00s [167/192] Installing qt5-srpm-macros-0: 100% | 0.0 B/s | 776.0 B | 00m00s [168/192] Installing perl-srpm-macros-0 100% | 0.0 B/s | 1.1 KiB | 00m00s [169/192] Installing package-notes-srpm 100% | 0.0 B/s | 2.1 KiB | 00m00s [170/192] Installing openblas-srpm-macr 100% | 0.0 B/s | 404.0 B | 00m00s [171/192] Installing ocaml-srpm-macros- 100% | 0.0 B/s | 2.1 KiB | 00m00s [172/192] Installing meson-srpm-macros- 100% | 0.0 B/s | 1.9 KiB | 00m00s [173/192] Installing kernel-srpm-macros 100% | 0.0 B/s | 2.3 KiB | 00m00s [174/192] Installing gnome-srpm-macros- 100% | 0.0 B/s | 4.1 KiB | 00m00s [175/192] Installing gnat-srpm-macros-0 100% | 0.0 B/s | 1.3 KiB | 00m00s [176/192] Installing ghc-srpm-macros-0: 100% | 0.0 B/s | 1.0 KiB | 00m00s [177/192] Installing gap-srpm-macros-0: 100% | 0.0 B/s | 2.7 KiB | 00m00s [178/192] Installing fpc-srpm-macros-0: 100% | 0.0 B/s | 420.0 B | 00m00s [179/192] Installing ansible-srpm-macro 100% | 0.0 B/s | 36.2 KiB | 00m00s [180/192] Installing rpm-build-0:6.1.0- 100% | 17.5 MiB/s | 322.1 KiB | 00m00s [181/192] Installing erlang-srpm-macros 100% | 0.0 B/s | 2.6 KiB | 00m00s [182/192] Installing pyproject-srpm-mac 100% | 0.0 B/s | 4.0 KiB | 00m00s [183/192] Installing redhat-rpm-config- 100% | 185.9 MiB/s | 190.4 KiB | 00m00s [184/192] Installing forge-srpm-macros- 100% | 0.0 B/s | 40.3 KiB | 00m00s [185/192] Installing fonts-srpm-macros- 100% | 0.0 B/s | 57.0 KiB | 00m00s [186/192] Installing go-srpm-macros-0:3 100% | 0.0 B/s | 63.0 KiB | 00m00s [187/192] Installing R-srpm-macros-0:1. 100% | 0.0 B/s | 4.4 KiB | 00m00s [188/192] Installing python-srpm-macros 100% | 0.0 B/s | 52.9 KiB | 00m00s [189/192] Installing rpm-plugin-selinux 100% | 0.0 B/s | 12.9 KiB | 00m00s [190/192] Installing which-0:2.25-2.fc4 100% | 4.9 MiB/s | 85.8 KiB | 00m00s [191/192] Installing shadow-utils-2:4.2 100% | 131.5 MiB/s | 3.9 MiB | 00m00s [192/192] Installing info-0:7.3-3.fc45. 100% | 56.4 KiB/s | 372.8 KiB | 00m07s Complete! Finish: installing minimal buildroot with dnf5 Start: creating root cache Finish: creating root cache Finish: chroot init INFO: Installed packages: INFO: R-srpm-macros-1.3.7-3.fc45.noarch add-determinism-0.7.3-3.fc45.x86_64 alternatives-1.33-6.fc45.x86_64 ansible-srpm-macros-1-22.fc45.noarch audit-libs-4.2.1-2.fc45.x86_64 bash-5.3.20-1.fc46.x86_64 binutils-2.47.50-15.fc46.x86_64 build-reproducibility-srpm-macros-0.7.3-3.fc45.noarch bzip2-1.0.8-24.fc45.x86_64 bzip2-libs-1.0.8-24.fc45.x86_64 ca-certificates-2026.2.90_v9.0.317-1.fc46.noarch cmake-srpm-macros-4.3.0-5.fc45.noarch coreutils-9.12-1.fc46.x86_64 coreutils-common-9.12-1.fc46.x86_64 cpio-2.15-10.fc45.x86_64 crypto-policies-20260713-2.gitc42da77.fc45.noarch curl-8.23.0~rc3-1.fc46.x86_64 cyrus-sasl-lib-2.1.28-37.fc45.x86_64 debugedit-5.3-3.fc45.x86_64 diffutils-3.12-6.fc45.x86_64 dwz-0.17-3.fc45.x86_64 ed-1.22.6-1.fc46.x86_64 efi-srpm-macros-6-9.fc45.noarch elfutils-0.196-1.fc46.x86_64 elfutils-debuginfod-client-0.196-1.fc46.x86_64 elfutils-libelf-0.196-1.fc46.x86_64 elfutils-libs-0.196-1.fc46.x86_64 erlang-srpm-macros-0.4.0-1.fc46.noarch fedora-gpg-keys-46-0.3.noarch fedora-release-46-0.1.noarch fedora-release-common-46-0.1.noarch fedora-release-identity-basic-46-0.1.noarch fedora-repos-46-0.3.noarch fedora-repos-rawhide-46-0.3.noarch file-5.48-3.fc46.x86_64 file-libs-5.48-3.fc46.x86_64 filesystem-3.18-59.fc45.x86_64 filesystem-srpm-macros-3.18-59.fc45.noarch findutils-4.11.0-2.fc45.x86_64 fips-provider-1.5.3-1.fc46.x86_64 fonts-srpm-macros-5.0.0-4.fc45.noarch forge-srpm-macros-0.4.0-5.fc45.noarch fpc-srpm-macros-1.3-17.fc45.noarch gap-srpm-macros-2-3.fc45.noarch gawk-5.4.1-1.fc45.x86_64 gdb-minimal-17.2-6.fc46.x86_64 gdbm-libs-1.26-1.fc46.x86_64 ghc-srpm-macros-1.10-2.fc45.noarch glibc-2.44.9000-5.fc46.x86_64 glibc-common-2.44.9000-5.fc46.x86_64 glibc-gconv-extra-2.44.9000-5.fc46.x86_64 glibc-minimal-langpack-2.44.9000-5.fc46.x86_64 gmp-6.3.0-6.fc45.x86_64 gnat-srpm-macros-7-3.fc45.noarch gnome-srpm-macros-1.0-2.fc45.noarch gnulib-l10n-20241231-4.fc45.noarch gnupg2-2.4.9-18.fc45.x86_64 gnupg2-dirmngr-2.4.9-18.fc45.x86_64 gnupg2-gpg-agent-2.4.9-18.fc45.x86_64 gnupg2-gpgconf-2.4.9-18.fc45.x86_64 gnupg2-keyboxd-2.4.9-18.fc45.x86_64 gnupg2-verify-2.4.9-18.fc45.x86_64 gnutls-3.8.13-5.fc46.x86_64 go-srpm-macros-3.8.0-3.fc45.noarch gpg-pubkey-4f50a6114cd5c6976a7f1179655a4b02f577861e-6888bc98 gpg-pubkey-b2e766fa50ca6fa2d5ed06fc09d879e09488fb64-6a6b46b4 gpg-pubkey-d924b10d3e810dabdd8b56b596e7e91491211fce-697c9899 gpgverify-2.2-5.fc45.noarch grep-3.12-4.fc45.x86_64 gzip-1.15-1.fc46.x86_64 ima-evm-utils-libs-1.6.2-12.fc45.x86_64 info-7.3-3.fc45.x86_64 jansson-2.14-5.fc45.x86_64 java-srpm-macros-1-9.fc45.noarch json-c-0.18-9.fc45.x86_64 kernel-srpm-macros-1.0-30.fc45.noarch keyutils-libs-1.6.3-8.fc45.x86_64 krb5-libs-1.22.2-9.fc45.x86_64 libacl-2.4.0-2.fc45.x86_64 libarchive-3.8.9-2.fc46.x86_64 libassuan-2.5.7-6.fc45.x86_64 libattr-2.6.0-2.fc45.x86_64 libblkid-2.42.4-2.fc46.x86_64 libbrotli-1.2.0-6.fc45.x86_64 libcap-2.78-2.fc45.x86_64 libcap-ng-0.9.6-1.fc46.x86_64 libcbor-0.14.0-3.fc45.x86_64 libcom_err-1.47.4-2.fc45.x86_64 libcurl-8.23.0~rc3-1.fc46.x86_64 libeconf-0.7.9-4.fc45.x86_64 libevent-2.1.13-1.fc46.x86_64 libfdisk-2.42.4-2.fc46.x86_64 libffi-3.8.0-1.fc46.x86_64 libfido2-1.17.0-6.fc46.x86_64 libfsverity-1.7-4.fc45.x86_64 libgcc-16.2.1-2.fc46.1.x86_64 libgcrypt-1.12.4-1.fc46.x86_64 libgomp-16.2.1-2.fc46.1.x86_64 libgpg-error-1.61-2.fc45.x86_64 libidn2-2.3.8-4.fc45.x86_64 libksba-1.8.1-1.fc46.x86_64 liblastlog2-2.42.4-2.fc46.x86_64 libmount-2.42.4-2.fc46.x86_64 libnghttp2-1.69.0-6.fc46.x86_64 libnghttp3-1.18.0-1.fc45.x86_64 libpfm-4.13.0-23.fc45.x86_64 libpkgconf-2.5.1-2.fc45.x86_64 libpsl-0.23.3-1.fc46.x86_64 libselinux-3.11-5.fc46.x86_64 libselinux-utils-3.11-5.fc46.x86_64 libsemanage-3.11-4.fc46.x86_64 libsepol-3.11-2.fc45.x86_64 libsmartcols-2.42.4-2.fc46.x86_64 libssh-0.12.2-1.fc45.x86_64 libssh-config-0.12.2-1.fc45.noarch libstdc++-16.2.1-2.fc46.1.x86_64 libtasn1-4.21.0-2.fc45.x86_64 libtool-ltdl-2.6.2-1.fc46.x86_64 libunistring-1.1-12.fc45.x86_64 libusb1-1.0.30-2.fc45.x86_64 libuuid-2.42.4-2.fc46.x86_64 libverto-0.3.2-13.fc45.x86_64 libxcrypt-4.5.2-4.fc45.x86_64 libxml2-2.15.4-1.fc46.x86_64 libzstd-1.5.7-6.fc45.x86_64 linkdupes-0.7.3-3.fc45.x86_64 lua-libs-5.5.1-2.fc46.x86_64 lua-srpm-macros-1-18.fc45.noarch lz4-libs-1.10.0-5.fc45.x86_64 meson-srpm-macros-1.12.1-2.fc46.noarch mpfr-4.2.2-4.fc45.x86_64 ncurses-base-6.6-3.fc45.noarch ncurses-libs-6.6-3.fc45.x86_64 nettle-4.0-5.fc45.x86_64 ngtcp2-1.22.1-3.fc45.x86_64 ngtcp2-crypto-ossl-1.22.1-3.fc45.x86_64 npth-1.8-5.fc45.x86_64 ocaml-srpm-macros-11-4.fc45.noarch openblas-srpm-macros-2-23.fc46.noarch openldap-2.6.15-1.fc46.x86_64 openssl-libs-4.0.3-1.fc46.x86_64 p11-kit-0.26.5-1.fc45.x86_64 p11-kit-trust-0.26.5-1.fc45.x86_64 package-notes-srpm-macros-0.20-2.fc45.noarch pam-libs-1.7.2-4.fc45.x86_64 patch-2.8-6.fc46.x86_64 pcre2-10.47-1.fc45.2.x86_64 pcre2-syntax-10.47-1.fc45.2.noarch perl-srpm-macros-1-65.fc45.noarch pkgconf-2.5.1-2.fc45.x86_64 pkgconf-m4-2.5.1-2.fc45.noarch pkgconf-pkg-config-2.5.1-2.fc45.x86_64 policycoreutils-3.11-2.fc45.x86_64 popt-1.19-11.fc45.x86_64 publicsuffix-list-dafsa-20260624-2.fc45.noarch pyproject-srpm-macros-1.24.0-1.fc46.noarch python-srpm-macros-3.15-2.fc45.noarch qt5-srpm-macros-5.15.18-3.fc45.noarch qt6-srpm-macros-6.11.2-1.fc46.noarch readline-8.3-7.fc46.x86_64 redhat-rpm-config-345-4.fc46.noarch redhat-systemd-presets-102-3.fc45.noarch redhat-systemd-presets-common-102-3.fc45.noarch rpm-6.1.0-1.fc46.x86_64 rpm-build-6.1.0-1.fc46.x86_64 rpm-build-libs-6.1.0-1.fc46.x86_64 rpm-libs-6.1.0-1.fc46.x86_64 rpm-plugin-selinux-6.1.0-1.fc46.x86_64 rpm-sequoia-1.10.3-1.fc46.x86_64 rpm-sign-libs-6.1.0-1.fc46.x86_64 rust-srpm-macros-28.5-2.fc45.noarch sed-4.10-2.fc45.x86_64 selinux-policy-45.21-1.fc46.noarch selinux-policy-targeted-45.21-1.fc46.noarch setup-2.15.1-2.fc45.noarch shadow-utils-4.20.0-1.fc45.x86_64 sqlite-libs-3.53.4-1.fc45.x86_64 systemd-libs-262-3.fc46.x86_64 systemd-standalone-sysusers-262-3.fc46.x86_64 tar-1.35-9.fc45.x86_64 tpm2-tss-4.2.0-1.fc45.x86_64 tree-sitter-srpm-macros-0.4.6-2.fc45.noarch unzip-6.0-71.fc45.x86_64 util-linux-2.42.4-2.fc46.x86_64 util-linux-core-2.42.4-2.fc46.x86_64 which-2.25-2.fc45.x86_64 xxhash-libs-0.8.4-1.fc46.x86_64 xz-5.8.4-1.fc46.x86_64 xz-libs-5.8.4-1.fc46.x86_64 zig-srpm-macros-1-9.fc45.noarch zip-3.0-46.fc45.x86_64 zlib-ng-compat-2.3.3-6.fc45.x86_64 zstd-1.5.7-6.fc45.x86_64 Start: buildsrpm Start: rpmbuild -bs Building target platforms: x86_64 Building for target x86_64 setting SOURCE_DATE_EPOCH=1788393600 Wrote: /builddir/build/SRPMS/python-llm-0.34-1.fc46.src.rpm Finish: rpmbuild -bs INFO: chroot_scan: 1 files copied to /var/lib/copr-rpmbuild/results/chroot_scan INFO: /var/lib/mock/fedora-rawhide-x86_64-1791974115.829543/root/var/log/dnf5.log INFO: chroot_scan: creating tarball /var/lib/copr-rpmbuild/results/chroot_scan.tar.gz /bin/tar: Removing leading `/' from member names Finish: buildsrpm INFO: Done(/var/lib/copr-rpmbuild/workspace/workdir-b_yo61sr/python-llm/python-llm.spec) Config(child) 0 minutes 15 seconds INFO: Results and/or logs in: /var/lib/copr-rpmbuild/results INFO: Cleaning up build root ('cleanup_on_success=True') Start: clean chroot INFO: unmounting tmpfs. Finish: clean chroot INFO: Start(/var/lib/copr-rpmbuild/results/python-llm-0.34-1.fc46.src.rpm) Config(fedora-rawhide-x86_64) Start(bootstrap): chroot init INFO: mounting tmpfs at /var/lib/mock/fedora-rawhide-x86_64-bootstrap-1791974115.829543/root. INFO: reusing tmpfs at /var/lib/mock/fedora-rawhide-x86_64-bootstrap-1791974115.829543/root. INFO: calling preinit hooks INFO: enabled root cache INFO: enabled package manager cache Start(bootstrap): cleaning package manager metadata Finish(bootstrap): cleaning package manager metadata Finish(bootstrap): chroot init Start: chroot init INFO: mounting tmpfs at /var/lib/mock/fedora-rawhide-x86_64-1791974115.829543/root. INFO: calling preinit hooks INFO: enabled root cache Start: unpacking root cache Finish: unpacking root cache INFO: enabled package manager cache Start: cleaning package manager metadata Finish: cleaning package manager metadata INFO: enabled HW Info plugin INFO: Buildroot is handled by package management downloaded with a bootstrap image: rpm-6.1.0-1.fc46.x86_64 rpm-sequoia-1.10.3-1.fc46.x86_64 dnf5-5.4.6.0-1.fc46.x86_64 dnf5-plugins-5.4.6.0-1.fc46.x86_64 Finish: chroot init Start: build phase for python-llm-0.34-1.fc46.src.rpm Start: build setup for python-llm-0.34-1.fc46.src.rpm Building target platforms: x86_64 Building for target x86_64 setting SOURCE_DATE_EPOCH=1788393600 Wrote: /builddir/build/SRPMS/python-llm-0.34-1.fc46.src.rpm Updating and loading repositories: fedora 100% | 59.2 KiB/s | 24.6 KiB | 00m00s Copr repository 100% | 5.6 KiB/s | 1.5 KiB | 00m00s Repositories loaded. Package Arch Version Repository Size Installing: make x86_64 1:4.4.1-13.fc45 fedora 1.8 MiB python3-devel x86_64 0:3.15.0-1.fc46 fedora 2.5 MiB python3-furo noarch 0:2025.12.19-7.fc45 fedora 369.2 KiB python3-llm-echo noarch 0:0.4-4.fc46 fedora 27.9 KiB python3-myst-parser noarch 0:5.1.0-3.fc45 fedora 880.8 KiB python3-numpy x86_64 1:2.5.4-1.fc46 fedora 43.1 MiB python3-pytest noarch 0:9.1.1-1.fc45 fedora 24.3 MiB python3-pytest-asyncio noarch 0:1.4.0-4.fc45 fedora 171.5 KiB python3-pytest-httpx noarch 0:0.36.0-3.fc45 fedora 185.6 KiB python3-pytest-recording noarch 0:0.14.0-1.fc46 fedora 94.9 KiB python3-sphinx-copybutton noarch 0:0.5.2-14.fc45 fedora 35.3 KiB python3-sphinx-markdown-builder noarch 0:0.6.11-1.fc46 fedora 199.5 KiB Installing dependencies: expat x86_64 0:2.8.3-1.fc46 fedora 338.4 KiB flexiblas x86_64 0:3.5.0-4.fc46 fedora 38.0 KiB flexiblas-netlib x86_64 0:3.5.0-4.fc46 fedora 16.3 MiB flexiblas-openblas-openmp x86_64 0:3.5.0-4.fc46 fedora 39.1 KiB less x86_64 0:710-1.fc46 fedora 488.7 KiB libgfortran x86_64 0:16.2.1-2.fc46.1 fedora 3.4 MiB libquadmath x86_64 0:16.2.1-2.fc46.1 fedora 321.9 KiB libxslt x86_64 0:1.1.43-10.fc46 fedora 471.8 KiB libyaml x86_64 0:0.2.5-19.fc45 fedora 138.5 KiB mpdecimal x86_64 0:4.0.1-4.fc45 fedora 221.2 KiB openblas x86_64 0:0.3.34-1.fc45 fedora 138.1 KiB openblas-openmp x86_64 0:0.3.34-1.fc45 fedora 44.8 MiB pyproject-rpm-macros noarch 0:1.24.0-1.fc46 fedora 169.0 KiB python-pip-wheel noarch 0:26.2.1-1.fc46 fedora 1.3 MiB python-rpm-macros noarch 0:3.15-2.fc45 fedora 28.0 KiB python3 x86_64 0:3.15.0-1.fc46 fedora 28.7 KiB python3-accessible-pygments noarch 0:0.0.5-13.fc45 fedora 1.5 MiB python3-annotated-types noarch 0:0.8.0-1.fc45 fedora 83.8 KiB python3-anyio noarch 0:4.15.1-1.fc46 fedora 1.7 MiB python3-babel noarch 0:2.18.0-4.fc45 fedora 30.3 MiB python3-beautifulsoup4 noarch 0:4.15.0-3.fc46 fedora 1.1 MiB python3-certifi noarch 0:2026.01.04-3.fc45 fedora 7.5 KiB python3-charset-normalizer noarch 0:3.5.2-1.fc46 fedora 478.1 KiB python3-click noarch 1:8.4.2-1.fc45 fedora 1.3 MiB python3-click-default-group noarch 0:1.2.2-29.fc45 fedora 17.1 KiB python3-condense-json noarch 0:1.1-2.fc45 fedora 75.6 KiB python3-dateutil noarch 1:2.9.0.post0-16.fc46 fedora 877.2 KiB python3-docutils noarch 0:0.23-3.fc46 fedora 5.6 MiB python3-h11 noarch 0:0.16.0-8.fc45 fedora 285.6 KiB python3-httpcore noarch 0:1.0.9-9.fc45 fedora 880.9 KiB python3-httpcore2 noarch 0:2.13.1-1.fc46 fedora 937.5 KiB python3-httpx noarch 0:0.28.1-14.fc45 fedora 1.0 MiB python3-httpx2 noarch 0:2.13.1-1.fc46 fedora 1.3 MiB python3-idna noarch 0:3.19-1.fc46 fedora 510.6 KiB python3-imagesize noarch 0:2.0.0-3.fc45 fedora 82.8 KiB python3-iniconfig noarch 0:2.3.0-5.fc45 fedora 49.6 KiB python3-jinja2 noarch 0:3.1.6-11.fc46 fedora 3.3 MiB python3-jiter x86_64 0:0.17.0-2.fc46 fedora 631.2 KiB python3-libs x86_64 0:3.15.0-1.fc46 fedora 48.3 MiB python3-llm noarch 0:0.34-1.fc46 fedora 1.6 MiB python3-lxml x86_64 0:6.1.2-1.fc46 fedora 5.8 MiB python3-markdown-it-py noarch 0:4.2.0-2.fc45 fedora 577.0 KiB python3-markupsafe x86_64 0:3.0.2-10.fc45 fedora 62.8 KiB python3-mdit-py-plugins noarch 0:0.6.1-2.fc45 fedora 379.5 KiB python3-mdurl noarch 0:0.1.2-16.fc45 fedora 44.3 KiB python3-numpy-f2py x86_64 1:2.5.4-1.fc46 fedora 2.1 MiB python3-openai noarch 0:3.24.0-1.fc46 fedora 15.7 MiB python3-packaging noarch 0:26.3-1.fc46 fedora 1.3 MiB python3-pip noarch 0:26.2.1-1.fc46 fedora 12.3 MiB python3-pluggy noarch 0:1.6.0-8.fc45 fedora 216.0 KiB python3-puremagic noarch 0:2.2.0-3.fc45 fedora 469.1 KiB python3-pydantic noarch 0:2.13.5-1.fc46 fedora 5.3 MiB python3-pydantic-core x86_64 0:2.46.5-4.fc46 fedora 5.4 MiB python3-pygments noarch 0:2.20.0-5.fc45 fedora 11.3 MiB python3-python-ulid noarch 0:4.0.1-3.fc46 copr_base 116.1 KiB python3-pyyaml x86_64 0:6.0.3-6.fc45 fedora 794.2 KiB python3-requests noarch 0:2.34.2-2.fc45 fedora 679.2 KiB python3-roman-numerals noarch 0:4.1.0-4.fc46 fedora 41.2 KiB python3-rpm-generators noarch 0:14-35.fc46 fedora 81.9 KiB python3-rpm-macros noarch 0:3.15-2.fc45 fedora 6.5 KiB python3-setuptools noarch 0:84.0.0-1.fc46 fedora 7.4 MiB python3-sniffio noarch 0:1.3.1-11.fc45 fedora 35.5 KiB python3-snowballstemmer noarch 0:3.1.1-2.fc45 fedora 1.8 MiB python3-soupsieve noarch 0:2.8.3-4.fc45 fedora 327.6 KiB python3-sphinx noarch 1:9.1.0-7.fc45 fedora 14.1 MiB python3-sphinx-basic-ng noarch 0:1.0.0-0.21.beta2.fc45 fedora 33.3 KiB python3-sphinx-theme-alabaster noarch 0:0.7.16-14.fc45 fedora 42.0 KiB python3-sqlite-fts4 noarch 0:1.0.3-4.fc45 fedora 42.6 KiB python3-sqlite-utils noarch 0:4.2.1-1.fc46 fedora 1.3 MiB python3-tabulate noarch 0:0.10.0-8.fc45 fedora 389.6 KiB python3-truststore noarch 0:0.10.4-3.fc45 fedora 124.8 KiB python3-typing-extensions noarch 0:4.16.0-4.fc46 fedora 554.7 KiB python3-typing-inspection noarch 0:0.4.4-1.fc46 fedora 93.9 KiB python3-urllib3 noarch 0:2.8.0-3.fc46 fedora 1.2 MiB python3-vcrpy noarch 0:8.3.0-2.fc45 fedora 345.8 KiB python3-wrapt x86_64 0:2.5.0-1.fc46 fedora 496.9 KiB tzdata noarch 0:2026e-1.fc46 fedora 1.3 MiB Transaction Summary: Installing: 89 packages Total size of inbound packages is 73 MiB. Need to download 30 MiB. After this operation, 335 MiB extra will be used (install 335 MiB, remove 0 B). [ 1/89] make-1:4.4.1-13.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 2/89] python3-pytest-0:9.1.1-1.fc45.n 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 3/89] python3-devel-0:3.15.0-1.fc46.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 4/89] python3-pygments-0:2.20.0-5.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 5/89] python3-sphinx-1:9.1.0-7.fc45.n 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 6/89] python3-docutils-0:0.23-3.fc46. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 7/89] python3-jinja2-0:3.1.6-11.fc46. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 8/89] python3-pyyaml-0:6.0.3-6.fc45.x 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [ 9/89] python3-iniconfig-0:2.3.0-5.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [10/89] python3-packaging-0:26.3-1.fc46 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [11/89] python3-pluggy-0:1.6.0-8.fc45.n 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [12/89] python3-httpx-0:0.28.1-14.fc45. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [13/89] python3-tabulate-0:0.10.0-8.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [14/89] python3-libs-0:3.15.0-1.fc46.x8 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [15/89] python3-typing-extensions-0:4.1 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [16/89] python3-babel-0:2.18.0-4.fc45.n 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [17/89] python3-imagesize-0:2.0.0-3.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [18/89] python3-requests-0:2.34.2-2.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [19/89] python3-roman-numerals-0:4.1.0- 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [20/89] python3-snowballstemmer-0:3.1.1 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [21/89] python3-sphinx-theme-alabaster- 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [22/89] python3-markupsafe-0:3.0.2-10.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [23/89] libyaml-0:0.2.5-19.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [24/89] python3-anyio-0:4.15.1-1.fc46.n 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [25/89] python3-certifi-0:2026.01.04-3. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [26/89] python3-httpcore-0:1.0.9-9.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [27/89] python3-idna-0:3.19-1.fc46.noar 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [28/89] python3-click-1:8.4.2-1.fc45.no 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [29/89] python3-pip-0:26.2.1-1.fc46.noa 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [30/89] python3-pydantic-0:2.13.5-1.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [31/89] expat-0:2.8.3-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [32/89] mpdecimal-0:4.0.1-4.fc45.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [33/89] python-pip-wheel-0:26.2.1-1.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [34/89] tzdata-0:2026e-1.fc46.noarch 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [35/89] python3-charset-normalizer-0:3. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [36/89] python3-urllib3-0:2.8.0-3.fc46. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [37/89] python3-h11-0:0.16.0-8.fc45.noa 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [38/89] less-0:710-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [39/89] python3-annotated-types-0:0.8.0 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [40/89] python3-pydantic-core-0:2.46.5- 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [41/89] python3-typing-inspection-0:0.4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [42/89] python3-dateutil-1:2.9.0.post0- 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [43/89] python3-0:3.15.0-1.fc46.x86_64 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [44/89] python3-setuptools-0:84.0.0-1.f 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [45/89] pyproject-rpm-macros-0:1.24.0-1 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [46/89] python-rpm-macros-0:3.15-2.fc45 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [47/89] python3-rpm-generators-0:14-35. 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [48/89] python3-rpm-macros-0:3.15-2.fc4 100% | 0.0 B/s | 0.0 B | 00m00s >>> Already downloaded [49/89] python3-myst-parser-0:5.1.0-3.f 100% | 38.0 MiB/s | 233.7 KiB | 00m00s [50/89] python3-pytest-asyncio-0:1.4.0- 100% | 9.1 MiB/s | 46.7 KiB | 00m00s [51/89] python3-furo-0:2025.12.19-7.fc4 100% | 19.1 MiB/s | 117.4 KiB | 00m00s [52/89] python3-pytest-httpx-0:0.36.0-3 100% | 8.2 MiB/s | 50.1 KiB | 00m00s [53/89] python3-sphinx-copybutton-0:0.5 100% | 488.5 KiB/s | 23.0 KiB | 00m00s [54/89] python3-pytest-recording-0:0.14 100% | 667.3 KiB/s | 43.4 KiB | 00m00s [55/89] python3-sphinx-markdown-builder 100% | 718.1 KiB/s | 57.4 KiB | 00m00s [56/89] python3-llm-echo-0:0.4-4.fc46.n 100% | 497.9 KiB/s | 18.9 KiB | 00m00s [57/89] python3-beautifulsoup4-0:4.15.0 100% | 24.7 MiB/s | 252.6 KiB | 00m00s [58/89] python3-sphinx-basic-ng-0:1.0.0 100% | 5.6 MiB/s | 34.5 KiB | 00m00s [59/89] python3-markdown-it-py-0:4.2.0- 100% | 41.6 MiB/s | 213.0 KiB | 00m00s [60/89] python3-mdit-py-plugins-0:0.6.1 100% | 36.3 MiB/s | 148.8 KiB | 00m00s [61/89] python3-numpy-1:2.5.4-1.fc46.x8 100% | 119.3 MiB/s | 8.5 MiB | 00m00s [62/89] python3-accessible-pygments-0:0 100% | 22.7 MiB/s | 1.3 MiB | 00m00s [63/89] flexiblas-netlib-0:3.5.0-4.fc46 100% | 249.2 MiB/s | 4.5 MiB | 00m00s [64/89] python3-numpy-f2py-1:2.5.4-1.fc 100% | 126.0 MiB/s | 515.9 KiB | 00m00s [65/89] python3-lxml-0:6.1.2-1.fc46.x86 100% | 168.1 MiB/s | 1.7 MiB | 00m00s [66/89] python3-vcrpy-0:8.3.0-2.fc45.no 100% | 1.9 MiB/s | 131.5 KiB | 00m00s [67/89] python3-soupsieve-0:2.8.3-4.fc4 100% | 25.5 MiB/s | 104.3 KiB | 00m00s [68/89] python3-mdurl-0:0.1.2-16.fc45.n 100% | 7.6 MiB/s | 31.3 KiB | 00m00s [69/89] python3-wrapt-0:2.5.0-1.fc46.x8 100% | 15.9 MiB/s | 146.3 KiB | 00m00s [70/89] python3-click-default-group-0:1 100% | 725.3 KiB/s | 16.0 KiB | 00m00s [71/89] python3-httpx2-0:2.13.1-1.fc46. 100% | 53.4 MiB/s | 273.2 KiB | 00m00s [72/89] python3-openai-0:3.24.0-1.fc46. 100% | 53.7 MiB/s | 3.4 MiB | 00m00s [73/89] python3-condense-json-0:1.1-2.f 100% | 342.9 KiB/s | 29.8 KiB | 00m00s [74/89] python3-sqlite-utils-0:4.2.1-1. 100% | 10.9 MiB/s | 255.7 KiB | 00m00s [75/89] python3-llm-0:0.34-1.fc46.noarc 100% | 2.8 MiB/s | 487.2 KiB | 00m00s [76/89] flexiblas-0:3.5.0-4.fc46.x86_64 100% | 7.3 MiB/s | 22.6 KiB | 00m00s [77/89] flexiblas-openblas-openmp-0:3.5 100% | 5.4 MiB/s | 16.5 KiB | 00m00s [78/89] libgfortran-0:16.2.1-2.fc46.1.x 100% | 192.8 MiB/s | 987.1 KiB | 00m00s [79/89] libquadmath-0:16.2.1-2.fc46.1.x 100% | 50.7 MiB/s | 207.7 KiB | 00m00s [80/89] libxslt-0:1.1.43-10.fc46.x86_64 100% | 62.4 MiB/s | 191.6 KiB | 00m00s [81/89] python3-httpcore2-0:2.13.1-1.fc 100% | 40.6 MiB/s | 166.2 KiB | 00m00s [82/89] python3-truststore-0:0.10.4-3.f 100% | 17.2 MiB/s | 52.8 KiB | 00m00s [83/89] python3-jiter-0:0.17.0-2.fc46.x 100% | 65.0 MiB/s | 266.2 KiB | 00m00s [84/89] python3-sniffio-0:1.3.1-11.fc45 100% | 6.7 MiB/s | 27.4 KiB | 00m00s [85/89] python3-sqlite-fts4-0:1.0.3-4.f 100% | 1.0 MiB/s | 21.6 KiB | 00m00s [86/89] openblas-openmp-0:0.3.34-1.fc45 100% | 203.2 MiB/s | 5.5 MiB | 00m00s [87/89] openblas-0:0.3.34-1.fc45.x86_64 100% | 23.5 MiB/s | 48.2 KiB | 00m00s [88/89] python3-puremagic-0:2.2.0-3.fc4 100% | 1.4 MiB/s | 132.4 KiB | 00m00s [89/89] python3-python-ulid-0:4.0.1-3.f 100% | 140.2 KiB/s | 44.9 KiB | 00m00s -------------------------------------------------------------------------------- [89/89] Total 100% | 41.2 MiB/s | 30.1 MiB | 00m01s Running transaction [ 1/91] Verify package files 100% | 366.0 B/s | 89.0 B | 00m00s [ 2/91] Prepare transaction 100% | 898.0 B/s | 89.0 B | 00m00s [ 3/91] Installing python-rpm-macros-0: 100% | 28.2 MiB/s | 28.9 KiB | 00m00s [ 4/91] Installing python3-rpm-macros-0 100% | 2.2 MiB/s | 6.8 KiB | 00m00s [ 5/91] Installing tzdata-0:2026e-1.fc4 100% | 58.6 MiB/s | 1.5 MiB | 00m00s [ 6/91] Installing libgfortran-0:16.2.1 100% | 486.0 MiB/s | 3.4 MiB | 00m00s [ 7/91] Installing pyproject-rpm-macros 100% | 167.4 MiB/s | 171.5 KiB | 00m00s [ 8/91] Installing openblas-0:0.3.34-1. 100% | 0.0 B/s | 139.9 KiB | 00m00s [ 9/91] Installing openblas-openmp-0:0. 100% | 658.3 MiB/s | 44.8 MiB | 00m00s [10/91] Installing less-0:710-1.fc46.x8 100% | 26.7 MiB/s | 492.0 KiB | 00m00s [11/91] Installing libxslt-0:1.1.43-10. 100% | 27.3 MiB/s | 474.9 KiB | 00m00s [12/91] Installing python-pip-wheel-0:2 100% | 634.1 MiB/s | 1.3 MiB | 00m00s [13/91] Installing mpdecimal-0:4.0.1-4. 100% | 217.5 MiB/s | 222.7 KiB | 00m00s [14/91] Installing expat-0:2.8.3-1.fc46 100% | 15.8 MiB/s | 340.5 KiB | 00m00s [15/91] Installing python3-libs-0:3.15. 100% | 386.4 MiB/s | 48.7 MiB | 00m00s [16/91] Installing python3-0:3.15.0-1.f 100% | 1.9 MiB/s | 30.4 KiB | 00m00s [17/91] Installing python3-typing-exten 100% | 543.9 MiB/s | 557.0 KiB | 00m00s [18/91] Installing python3-idna-0:3.19- 100% | 26.6 MiB/s | 518.5 KiB | 00m00s [19/91] Installing python3-pygments-0:2 100% | 226.2 MiB/s | 11.5 MiB | 00m00s [20/91] Installing python3-anyio-0:4.15 100% | 295.2 MiB/s | 1.8 MiB | 00m00s [21/91] Installing python3-docutils-0:0 100% | 172.6 MiB/s | 5.7 MiB | 00m00s [22/91] Installing python3-packaging-0: 100% | 326.5 MiB/s | 1.3 MiB | 00m00s [23/91] Installing python3-pluggy-0:1.6 100% | 217.2 MiB/s | 222.4 KiB | 00m00s [24/91] Installing python3-click-1:8.4. 100% | 443.7 MiB/s | 1.3 MiB | 00m00s [25/91] Installing python3-click-defaul 100% | 0.0 B/s | 19.7 KiB | 00m00s [26/91] Installing python3-tabulate-0:0 100% | 24.0 MiB/s | 392.7 KiB | 00m00s [27/91] Installing python3-certifi-0:20 100% | 2.8 MiB/s | 11.3 KiB | 00m00s [28/91] Installing python3-pip-0:26.2.1 100% | 202.2 MiB/s | 12.5 MiB | 00m00s [29/91] Installing python3-h11-0:0.16.0 100% | 286.7 MiB/s | 293.6 KiB | 00m00s [30/91] Installing python3-truststore-0 100% | 126.8 MiB/s | 129.9 KiB | 00m00s [31/91] Installing python3-httpcore2-0: 100% | 311.9 MiB/s | 958.3 KiB | 00m00s [32/91] Installing python3-httpx2-0:2.1 100% | 338.1 MiB/s | 1.4 MiB | 00m00s [33/91] Installing python3-httpcore-0:1 100% | 293.4 MiB/s | 901.4 KiB | 00m00s [34/91] Installing python3-httpx-0:0.28 100% | 335.4 MiB/s | 1.0 MiB | 00m00s [35/91] Installing python3-rpm-generato 100% | 81.1 MiB/s | 83.1 KiB | 00m00s [36/91] Installing python3-accessible-p 100% | 199.3 MiB/s | 1.6 MiB | 00m00s [37/91] Installing python3-urllib3-0:2. 100% | 300.4 MiB/s | 1.2 MiB | 00m00s [38/91] Installing python3-pydantic-cor 100% | 411.9 MiB/s | 5.4 MiB | 00m00s [39/91] Installing python3-typing-inspe 100% | 95.7 MiB/s | 98.0 KiB | 00m00s [40/91] Installing python3-iniconfig-0: 100% | 17.6 MiB/s | 54.0 KiB | 00m00s [41/91] Installing python3-pytest-0:9.1 100% | 387.9 MiB/s | 24.4 MiB | 00m00s [42/91] Installing python3-lxml-0:6.1.2 100% | 366.6 MiB/s | 5.9 MiB | 00m00s [43/91] Installing python3-soupsieve-0: 100% | 162.9 MiB/s | 333.7 KiB | 00m00s [44/91] Installing python3-beautifulsou 100% | 216.8 MiB/s | 1.1 MiB | 00m00s [45/91] Installing python3-babel-0:2.18 100% | 367.9 MiB/s | 30.5 MiB | 00m00s [46/91] Installing python3-imagesize-0: 100% | 83.9 MiB/s | 85.9 KiB | 00m00s [47/91] Installing python3-roman-numera 100% | 43.1 MiB/s | 44.1 KiB | 00m00s [48/91] Installing python3-snowballstem 100% | 361.6 MiB/s | 1.8 MiB | 00m00s [49/91] Installing python3-sphinx-theme 100% | 45.5 MiB/s | 46.6 KiB | 00m00s [50/91] Installing python3-markupsafe-0 100% | 65.5 MiB/s | 67.1 KiB | 00m00s [51/91] Installing python3-jinja2-0:3.1 100% | 412.9 MiB/s | 3.3 MiB | 00m00s [52/91] Installing python3-mdurl-0:0.1. 100% | 48.5 MiB/s | 49.7 KiB | 00m00s [53/91] Installing python3-markdown-it- 100% | 30.3 MiB/s | 621.1 KiB | 00m00s [54/91] Installing python3-mdit-py-plug 100% | 101.1 MiB/s | 413.9 KiB | 00m00s [55/91] Installing python3-wrapt-0:2.5. 100% | 247.8 MiB/s | 507.4 KiB | 00m00s [56/91] Installing python3-condense-jso 100% | 76.5 MiB/s | 78.3 KiB | 00m00s [57/91] Installing python3-puremagic-0: 100% | 27.7 MiB/s | 482.4 KiB | 00m00s [58/91] Installing python3-charset-norm 100% | 28.0 MiB/s | 488.2 KiB | 00m00s [59/91] Installing python3-requests-0:2 100% | 135.2 MiB/s | 692.0 KiB | 00m00s [60/91] Installing python3-sphinx-1:9.1 100% | 223.3 MiB/s | 14.3 MiB | 00m00s [61/91] Installing python3-sphinx-basic 100% | 22.0 MiB/s | 45.1 KiB | 00m00s [62/91] Installing python3-jiter-0:0.17 100% | 309.9 MiB/s | 634.8 KiB | 00m00s [63/91] Installing python3-sniffio-0:1. 100% | 40.2 MiB/s | 41.1 KiB | 00m00s [64/91] Installing python3-annotated-ty 100% | 84.9 MiB/s | 86.9 KiB | 00m00s [65/91] Installing python3-pydantic-0:2 100% | 204.5 MiB/s | 5.3 MiB | 00m00s [66/91] Installing python3-openai-0:3.2 100% | 161.4 MiB/s | 16.9 MiB | 00m00s [67/91] Installing python3-dateutil-1:2 100% | 290.0 MiB/s | 890.8 KiB | 00m00s [68/91] Installing python3-sqlite-fts4- 100% | 44.1 MiB/s | 45.2 KiB | 00m00s [69/91] Installing python3-sqlite-utils 100% | 70.2 MiB/s | 1.3 MiB | 00m00s [70/91] Installing python3-python-ulid- 100% | 6.6 MiB/s | 121.1 KiB | 00m00s [71/91] Installing python3-setuptools-0 100% | 270.1 MiB/s | 7.6 MiB | 00m00s [72/91] Installing libquadmath-0:16.2.1 100% | 315.6 MiB/s | 323.2 KiB | 00m00s [73/91] Installing flexiblas-netlib-0:3 100% | 307.6 MiB/s | 16.3 MiB | 00m00s [74/91] Installing flexiblas-0:3.5.0-4. 100% | 0.0 B/s | 39.2 KiB | 00m00s [75/91] Installing flexiblas-openblas-o 100% | 13.0 MiB/s | 40.0 KiB | 00m00s [76/91] Installing python3-numpy-1:2.5. 100% | 358.8 MiB/s | 43.4 MiB | 00m00s [77/91] Installing python3-numpy-f2py-1 100% | 87.8 MiB/s | 2.2 MiB | 00m00s [78/91] Installing libyaml-0:0.2.5-19.f 100% | 136.6 MiB/s | 139.9 KiB | 00m00s [79/91] Installing python3-pyyaml-0:6.0 100% | 197.3 MiB/s | 808.2 KiB | 00m00s [80/91] Installing python3-vcrpy-0:8.3. 100% | 118.7 MiB/s | 364.7 KiB | 00m00s [81/91] Installing python3-llm-0:0.34-1 100% | 79.7 MiB/s | 1.6 MiB | 00m00s [82/91] Installing python3-llm-echo-0:0 100% | 29.2 MiB/s | 29.9 KiB | 00m00s [83/91] Installing python3-pytest-recor 100% | 99.6 MiB/s | 102.0 KiB | 00m00s [84/91] Installing python3-myst-parser- 100% | 46.4 MiB/s | 902.5 KiB | 00m00s [85/91] Installing python3-furo-0:2025. 100% | 127.0 MiB/s | 390.1 KiB | 00m00s [86/91] Installing python3-sphinx-copyb 100% | 38.3 MiB/s | 39.2 KiB | 00m00s [87/91] Installing python3-sphinx-markd 100% | 200.9 MiB/s | 205.7 KiB | 00m00s [88/91] Installing python3-pytest-async 100% | 170.9 MiB/s | 175.0 KiB | 00m00s [89/91] Installing python3-pytest-httpx 100% | 93.7 MiB/s | 191.9 KiB | 00m00s [90/91] Installing python3-devel-0:3.15 100% | 100.2 MiB/s | 2.5 MiB | 00m00s [91/91] Installing make-1:4.4.1-13.fc45 100% | 19.6 MiB/s | 1.8 MiB | 00m00s Warning: skipped OpenPGP checks for 1 package from repository: copr_base Complete! Building target platforms: x86_64 Building for target x86_64 setting SOURCE_DATE_EPOCH=1788393600 Wrote: /builddir/build/SRPMS/python-llm-0.34-1.fc46.src.rpm Updating and loading repositories: fedora 100% | 81.7 KiB/s | 24.6 KiB | 00m00s Copr repository 100% | 9.6 KiB/s | 1.5 KiB | 00m00s Repositories loaded. Package "make-1:4.4.1-13.fc45.x86_64" is already installed. Package "python3-devel-3.15.0-1.fc46.x86_64" is already installed. Package "python3-furo-2025.12.19-7.fc45.noarch" is already installed. Package "python3-myst-parser-5.1.0-3.fc45.noarch" is already installed. Package "python3-pytest-9.1.1-1.fc45.noarch" is already installed. Package "python3-pytest-asyncio-1.4.0-4.fc45.noarch" is already installed. Package "python3-pytest-httpx-0.36.0-3.fc45.noarch" is already installed. Package "python3-pytest-recording-0.14.0-1.fc46.noarch" is already installed. Package "python3-sphinx-copybutton-0.5.2-14.fc45.noarch" is already installed. Package "python3-sphinx-markdown-builder-0.6.11-1.fc46.noarch" is already installed. Package "python3-llm-echo-0.4-4.fc46.noarch" is already installed. Package "python3-numpy-1:2.5.4-1.fc46.x86_64" is already installed. Nothing to do. Finish: build setup for python-llm-0.34-1.fc46.src.rpm Start: rpmbuild python-llm-0.34-1.fc46.src.rpm Building target platforms: x86_64 Building for target x86_64 setting SOURCE_DATE_EPOCH=1788393600 Executing(mkbuilddir): /bin/sh -e /var/tmp/rpm-tmp.GuDhbl Creating(rpmbuild.env): /builddir/build/BUILD/python-llm-0.34-build/rpmbuild.env RPM_SOURCE_DIR="/builddir/build/SOURCES" RPM_BUILD_DIR="/builddir/build/BUILD/python-llm-0.34-build" RPM_OPT_FLAGS="-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer" RPM_LD_FLAGS="-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes " RPM_ARCH="x86_64" RPM_OS="linux" RPM_BUILD_NCPUS="4" RPM_SPECPARTS_DIR="/builddir/build/BUILD/python-llm-0.34-build/SPECPARTS" export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS RPM_SPECPARTS_DIR RPM_LD_FLAGS RPM_DOC_DIR="/usr/share/doc" export RPM_DOC_DIR RPM_PACKAGE_NAME="python-llm" RPM_PACKAGE_VERSION="0.34" RPM_PACKAGE_RELEASE="1.fc46" export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE LANG=C.UTF-8 export LANG unset CDPATH DISPLAY ||: unset DEBUGINFOD_URLS ||: unset RPM_CONFIG_DIR ||: RPM_BUILD_ROOT="/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT" export RPM_BUILD_ROOT PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:/usr/lib64/pkgconfig:/usr/share/pkgconfig" export PKG_CONFIG_PATH CONFIG_SITE=${CONFIG_SITE:-NONE} export CONFIG_SITE Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.ubvEu5 + umask 022 + cd /builddir/build/BUILD/python-llm-0.34-build + cd /builddir/build/BUILD/python-llm-0.34-build + rm -rf llm-0.34 + /usr/bin/rpmuncompress -x /builddir/build/SOURCES/llm-0.34.tar.gz + STATUS=0 + '[' 0 -ne 0 ']' + cd llm-0.34 + /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w . + /usr/bin/rpmuncompress /builddir/build/SOURCES/0001-Relax-reqs.patch + /usr/bin/patch -p1 -s --fuzz=0 --no-backup-if-mismatch -f + /usr/bin/rpmuncompress /builddir/build/SOURCES/0002-Skip-tests-failing-with-sqlite-3.51.patch + /usr/bin/patch -p1 -s --fuzz=0 --no-backup-if-mismatch -f + /usr/bin/rpmuncompress /builddir/build/SOURCES/0003-Skip-tests-which-requires-network-access.patch + /usr/bin/patch -p1 -s --fuzz=0 --no-backup-if-mismatch -f + RPM_EC=0 ++ jobs -p + exit 0 Executing(%generate_buildrequires): /bin/sh -e /var/tmp/rpm-tmp.N5meZw + umask 022 + cd /builddir/build/BUILD/python-llm-0.34-build + cd llm-0.34 + echo pyproject-rpm-macros + echo python3-devel + echo 'python3dist(packaging)' + echo 'python3dist(pip) >= 19' + '[' -f pyproject.toml ']' + echo '(python3dist(tomli) if python3-devel < 3.11)' + rm -rfv '*.dist-info/' + '[' -f /usr/bin/python3 ']' + mkdir -p /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir + echo -n + CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + FFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + FCFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + VALAFLAGS=-g + RUSTFLAGS='-Copt-level=3 -Cdebuginfo=2 -Ccodegen-units=1 -Cstrip=none -Cforce-frame-pointers=yes --cap-lints=warn' + LDFLAGS='-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 ' + LT_SYS_LIBRARY_PATH=/usr/lib64: + CC=gcc + CXX=g++ + TMPDIR=/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir + RPM_TOXENV=py315 + FEDORA=46 + HOSTNAME=rpmbuild + /usr/bin/python3 -Bs /usr/lib/rpm/redhat/pyproject_buildrequires.py --generate-extras --python3_pkgversion 3 --wheeldir /builddir/build/BUILD/python-llm-0.34-build/pyproject-wheeldir --output /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-buildrequires --dep-overrides-file /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-dep-overrides Handling setuptools from build-system.requires Requirement satisfied: setuptools (installed: setuptools 84.0.0) running egg_info creating llm.egg-info writing llm.egg-info/PKG-INFO writing dependency_links to llm.egg-info/dependency_links.txt writing entry points to llm.egg-info/entry_points.txt writing requirements to llm.egg-info/requires.txt writing top-level names to llm.egg-info/top_level.txt writing manifest file 'llm.egg-info/SOURCES.txt' reading manifest file 'llm.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' adding license file 'LICENSE' writing manifest file 'llm.egg-info/SOURCES.txt' running dist_info writing llm.egg-info/PKG-INFO writing dependency_links to llm.egg-info/dependency_links.txt writing entry points to llm.egg-info/entry_points.txt writing requirements to llm.egg-info/requires.txt writing top-level names to llm.egg-info/top_level.txt reading manifest file 'llm.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' adding license file 'LICENSE' writing manifest file 'llm.egg-info/SOURCES.txt' creating '/builddir/build/BUILD/python-llm-0.34-build/llm-0.34/llm-0.34.dist-info' Handling click from hook generated metadata: Requires-Dist (llm) Requirement satisfied: click (installed: click 8.4.2) Handling httpx2 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: httpx2 (installed: httpx2 2.13.1) Handling condense-json>=1.1 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: condense-json>=1.1 (installed: condense-json 1.1) Handling openai>=2.21.0 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: openai>=2.21.0 (installed: openai 3.24.0) Handling click-default-group>=1.2.2 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: click-default-group>=1.2.2 (installed: click-default-group 1.2.2) Handling sqlite-utils>=4.0 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: sqlite-utils>=4.0 (installed: sqlite-utils 4.2.1) Handling pydantic>=2.0.0 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: pydantic>=2.0.0 (installed: pydantic 2.13.5) Handling typing-extensions from hook generated metadata: Requires-Dist (llm) Requirement satisfied: typing-extensions (installed: typing-extensions 4.16.0) Handling PyYAML from hook generated metadata: Requires-Dist (llm) Requirement satisfied: PyYAML (installed: PyYAML 6.0.3) Handling pluggy from hook generated metadata: Requires-Dist (llm) Requirement satisfied: pluggy (installed: pluggy 1.6.0) Handling python-ulid from hook generated metadata: Requires-Dist (llm) Requirement satisfied: python-ulid (installed: python-ulid 4.0.1) Handling setuptools from hook generated metadata: Requires-Dist (llm) Requirement satisfied: setuptools (installed: setuptools 84.0.0) Handling pip from hook generated metadata: Requires-Dist (llm) Requirement satisfied: pip (installed: pip 26.2.1) Handling pyreadline3; sys_platform == "win32" from hook generated metadata: Requires-Dist (llm) Ignoring alien requirement: pyreadline3; sys_platform == "win32" Handling puremagic from hook generated metadata: Requires-Dist (llm) Requirement satisfied: puremagic (installed: puremagic 2.2.0) + cat /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-buildrequires + rm -rfv llm-0.34.dist-info/ removed 'llm-0.34.dist-info/licenses/LICENSE' removed directory 'llm-0.34.dist-info/licenses' removed 'llm-0.34.dist-info/METADATA' removed 'llm-0.34.dist-info/entry_points.txt' removed 'llm-0.34.dist-info/top_level.txt' removed directory 'llm-0.34.dist-info/' + RPM_EC=0 ++ jobs -p + exit 0 Wrote: /builddir/build/SRPMS/python-llm-0.34-1.fc46.buildreqs.nosrc.rpm INFO: Going to install missing dynamic buildrequires Updating and loading repositories: fedora 100% | 117.6 KiB/s | 24.6 KiB | 00m00s Copr repository 100% | 9.4 KiB/s | 1.5 KiB | 00m00s Repositories loaded. Package "make-1:4.4.1-13.fc45.x86_64" is already installed. Package "pyproject-rpm-macros-1.24.0-1.fc46.noarch" is already installed. Package "python3-devel-3.15.0-1.fc46.x86_64" is already installed. Package "python3-furo-2025.12.19-7.fc45.noarch" is already installed. Package "python3-myst-parser-5.1.0-3.fc45.noarch" is already installed. Package "python3-pytest-9.1.1-1.fc45.noarch" is already installed. Package "python3-pytest-asyncio-1.4.0-4.fc45.noarch" is already installed. Package "python3-pytest-httpx-0.36.0-3.fc45.noarch" is already installed. Package "python3-pytest-recording-0.14.0-1.fc46.noarch" is already installed. Package "python3-sphinx-copybutton-0.5.2-14.fc45.noarch" is already installed. Package "python3-sphinx-markdown-builder-0.6.11-1.fc46.noarch" is already installed. Package "python3-click-1:8.4.2-1.fc45.noarch" is already installed. Package "python3-click-default-group-1.2.2-29.fc45.noarch" is already installed. Package "python3-condense-json-1.1-2.fc45.noarch" is already installed. Package "python3-httpx2-2.13.1-1.fc46.noarch" is already installed. Package "python3-llm-echo-0.4-4.fc46.noarch" is already installed. Package "python3-numpy-1:2.5.4-1.fc46.x86_64" is already installed. Package "python3-openai-3.24.0-1.fc46.noarch" is already installed. Package "python3-packaging-26.3-1.fc46.noarch" is already installed. Package "python3-pip-26.2.1-1.fc46.noarch" is already installed. Package "python3-pip-26.2.1-1.fc46.noarch" is already installed. Package "python3-pluggy-1.6.0-8.fc45.noarch" is already installed. Package "python3-puremagic-2.2.0-3.fc45.noarch" is already installed. Package "python3-pydantic-2.13.5-1.fc46.noarch" is already installed. Package "python3-python-ulid-4.0.1-3.fc46.noarch" is already installed. Package "python3-pyyaml-6.0.3-6.fc45.x86_64" is already installed. Package "python3-setuptools-84.0.0-1.fc46.noarch" is already installed. Package "python3-sqlite-utils-4.2.1-1.fc46.noarch" is already installed. Package "python3-typing-extensions-4.16.0-4.fc46.noarch" is already installed. Nothing to do. Building target platforms: x86_64 Building for target x86_64 setting SOURCE_DATE_EPOCH=1788393600 Executing(%generate_buildrequires): /bin/sh -e /var/tmp/rpm-tmp.tlabV5 + umask 022 + cd /builddir/build/BUILD/python-llm-0.34-build + cd llm-0.34 + echo pyproject-rpm-macros + echo python3-devel + echo 'python3dist(packaging)' + echo 'python3dist(pip) >= 19' + '[' -f pyproject.toml ']' + echo '(python3dist(tomli) if python3-devel < 3.11)' + rm -rfv '*.dist-info/' + '[' -f /usr/bin/python3 ']' + mkdir -p /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir + echo -n + CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + FFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + FCFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + VALAFLAGS=-g + RUSTFLAGS='-Copt-level=3 -Cdebuginfo=2 -Ccodegen-units=1 -Cstrip=none -Cforce-frame-pointers=yes --cap-lints=warn' + LDFLAGS='-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 ' + LT_SYS_LIBRARY_PATH=/usr/lib64: + CC=gcc + CXX=g++ + TMPDIR=/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir + RPM_TOXENV=py315 + FEDORA=46 + HOSTNAME=rpmbuild + /usr/bin/python3 -Bs /usr/lib/rpm/redhat/pyproject_buildrequires.py --generate-extras --python3_pkgversion 3 --wheeldir /builddir/build/BUILD/python-llm-0.34-build/pyproject-wheeldir --output /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-buildrequires --dep-overrides-file /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-dep-overrides Handling setuptools from build-system.requires Requirement satisfied: setuptools (installed: setuptools 84.0.0) running egg_info writing llm.egg-info/PKG-INFO writing dependency_links to llm.egg-info/dependency_links.txt writing entry points to llm.egg-info/entry_points.txt writing requirements to llm.egg-info/requires.txt writing top-level names to llm.egg-info/top_level.txt reading manifest file 'llm.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' adding license file 'LICENSE' writing manifest file 'llm.egg-info/SOURCES.txt' running dist_info writing llm.egg-info/PKG-INFO writing dependency_links to llm.egg-info/dependency_links.txt writing entry points to llm.egg-info/entry_points.txt writing requirements to llm.egg-info/requires.txt writing top-level names to llm.egg-info/top_level.txt reading manifest file 'llm.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' adding license file 'LICENSE' writing manifest file 'llm.egg-info/SOURCES.txt' creating '/builddir/build/BUILD/python-llm-0.34-build/llm-0.34/llm-0.34.dist-info' Handling click from hook generated metadata: Requires-Dist (llm) Requirement satisfied: click (installed: click 8.4.2) Handling httpx2 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: httpx2 (installed: httpx2 2.13.1) Handling condense-json>=1.1 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: condense-json>=1.1 (installed: condense-json 1.1) Handling openai>=2.21.0 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: openai>=2.21.0 (installed: openai 3.24.0) Handling click-default-group>=1.2.2 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: click-default-group>=1.2.2 (installed: click-default-group 1.2.2) Handling sqlite-utils>=4.0 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: sqlite-utils>=4.0 (installed: sqlite-utils 4.2.1) Handling pydantic>=2.0.0 from hook generated metadata: Requires-Dist (llm) Requirement satisfied: pydantic>=2.0.0 (installed: pydantic 2.13.5) Handling typing-extensions from hook generated metadata: Requires-Dist (llm) Requirement satisfied: typing-extensions (installed: typing-extensions 4.16.0) Handling PyYAML from hook generated metadata: Requires-Dist (llm) Requirement satisfied: PyYAML (installed: PyYAML 6.0.3) Handling pluggy from hook generated metadata: Requires-Dist (llm) Requirement satisfied: pluggy (installed: pluggy 1.6.0) Handling python-ulid from hook generated metadata: Requires-Dist (llm) Requirement satisfied: python-ulid (installed: python-ulid 4.0.1) Handling setuptools from hook generated metadata: Requires-Dist (llm) Requirement satisfied: setuptools (installed: setuptools 84.0.0) Handling pip from hook generated metadata: Requires-Dist (llm) Requirement satisfied: pip (installed: pip 26.2.1) Handling pyreadline3; sys_platform == "win32" from hook generated metadata: Requires-Dist (llm) Ignoring alien requirement: pyreadline3; sys_platform == "win32" Handling puremagic from hook generated metadata: Requires-Dist (llm) Requirement satisfied: puremagic (installed: puremagic 2.2.0) + cat /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-buildrequires + rm -rfv llm-0.34.dist-info/ removed 'llm-0.34.dist-info/licenses/LICENSE' removed directory 'llm-0.34.dist-info/licenses' removed 'llm-0.34.dist-info/METADATA' removed 'llm-0.34.dist-info/top_level.txt' removed 'llm-0.34.dist-info/entry_points.txt' removed directory 'llm-0.34.dist-info/' + RPM_EC=0 ++ jobs -p + exit 0 Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.mtychi + umask 022 + cd /builddir/build/BUILD/python-llm-0.34-build + CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + export CFLAGS + CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + export CXXFLAGS + FFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + export FFLAGS + FCFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + export FCFLAGS + VALAFLAGS=-g + export VALAFLAGS + RUSTFLAGS='-Copt-level=3 -Cdebuginfo=2 -Ccodegen-units=1 -Cstrip=none -Cforce-frame-pointers=yes -Clink-arg=-specs=/usr/lib/rpm/redhat/redhat-package-notes --cap-lints=warn' + export RUSTFLAGS + LDFLAGS='-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes ' + export LDFLAGS + LT_SYS_LIBRARY_PATH=/usr/lib64: + export LT_SYS_LIBRARY_PATH + CC=gcc + export CC + CXX=g++ + export CXX + cd llm-0.34 + mkdir -p /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir + CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + FFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + FCFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + VALAFLAGS=-g + RUSTFLAGS='-Copt-level=3 -Cdebuginfo=2 -Ccodegen-units=1 -Cstrip=none -Cforce-frame-pointers=yes -Clink-arg=-specs=/usr/lib/rpm/redhat/redhat-package-notes --cap-lints=warn' + LDFLAGS='-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes ' + LT_SYS_LIBRARY_PATH=/usr/lib64: + CC=gcc + CXX=g++ + TMPDIR=/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir + /usr/bin/python3 -Bs /usr/lib/rpm/redhat/pyproject_wheel.py /builddir/build/BUILD/python-llm-0.34-build/pyproject-wheeldir Processing ./. Preparing metadata (pyproject.toml): started Running command Preparing metadata (pyproject.toml) running dist_info creating /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info writing /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info/PKG-INFO writing dependency_links to /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info/dependency_links.txt writing entry points to /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info/entry_points.txt writing requirements to /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info/requires.txt writing top-level names to /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info/top_level.txt writing manifest file '/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info/SOURCES.txt' reading manifest file '/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' adding license file 'LICENSE' writing manifest file '/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm.egg-info/SOURCES.txt' creating '/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-modern-metadata-es1xoemd/llm-0.34.dist-info' Preparing metadata (pyproject.toml): finished with status 'done' Building wheels for collected packages: llm Building wheel for llm (pyproject.toml): started Running command Building wheel for llm (pyproject.toml) running bdist_wheel running build running build_py creating build/lib/llm copying llm/utils.py -> build/lib/llm copying llm/tools.py -> build/lib/llm copying llm/templates.py -> build/lib/llm copying llm/serialization.py -> build/lib/llm copying llm/plugins.py -> build/lib/llm copying llm/parts.py -> build/lib/llm copying llm/models.py -> build/lib/llm copying llm/migrations.py -> build/lib/llm copying llm/logs.py -> build/lib/llm copying llm/hookspecs.py -> build/lib/llm copying llm/errors.py -> build/lib/llm copying llm/embeddings_migrations.py -> build/lib/llm copying llm/embeddings.py -> build/lib/llm copying llm/cli.py -> build/lib/llm copying llm/__main__.py -> build/lib/llm copying llm/__init__.py -> build/lib/llm creating build/lib/llm/default_plugins copying llm/default_plugins/openai_models.py -> build/lib/llm/default_plugins copying llm/default_plugins/default_tools.py -> build/lib/llm/default_plugins copying llm/default_plugins/__init__.py -> build/lib/llm/default_plugins running egg_info writing llm.egg-info/PKG-INFO writing dependency_links to llm.egg-info/dependency_links.txt writing entry points to llm.egg-info/entry_points.txt writing requirements to llm.egg-info/requires.txt writing top-level names to llm.egg-info/top_level.txt reading manifest file 'llm.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' adding license file 'LICENSE' writing manifest file 'llm.egg-info/SOURCES.txt' copying llm/py.typed -> build/lib/llm installing to build/bdist.linux-x86_64/wheel running install running install_lib creating build/bdist.linux-x86_64/wheel creating build/bdist.linux-x86_64/wheel/llm copying build/lib/llm/py.typed -> build/bdist.linux-x86_64/wheel/./llm creating build/bdist.linux-x86_64/wheel/llm/default_plugins copying build/lib/llm/default_plugins/__init__.py -> build/bdist.linux-x86_64/wheel/./llm/default_plugins copying build/lib/llm/default_plugins/default_tools.py -> build/bdist.linux-x86_64/wheel/./llm/default_plugins copying build/lib/llm/default_plugins/openai_models.py -> build/bdist.linux-x86_64/wheel/./llm/default_plugins copying build/lib/llm/__init__.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/__main__.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/cli.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/embeddings.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/embeddings_migrations.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/errors.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/hookspecs.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/logs.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/migrations.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/models.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/parts.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/plugins.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/serialization.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/templates.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/tools.py -> build/bdist.linux-x86_64/wheel/./llm copying build/lib/llm/utils.py -> build/bdist.linux-x86_64/wheel/./llm running install_egg_info Copying llm.egg-info to build/bdist.linux-x86_64/wheel/./llm-0.34-py3.15.egg-info running install_scripts creating build/bdist.linux-x86_64/wheel/llm-0.34.dist-info/WHEEL creating '/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-ephem-wheel-cache-ahuc2fug/wheels/0a/96/33/c88d2556e34b5f4adcf73b314ce1e110e7de8919096ff789ed/tmpvuit8fbq/.tmp-gr5xutc3/llm-0.34-py3-none-any.whl' and adding 'build/bdist.linux-x86_64/wheel' to it adding 'llm/__init__.py' adding 'llm/__main__.py' adding 'llm/cli.py' adding 'llm/embeddings.py' adding 'llm/embeddings_migrations.py' adding 'llm/errors.py' adding 'llm/hookspecs.py' adding 'llm/logs.py' adding 'llm/migrations.py' adding 'llm/models.py' adding 'llm/parts.py' adding 'llm/plugins.py' adding 'llm/py.typed' adding 'llm/serialization.py' adding 'llm/templates.py' adding 'llm/tools.py' adding 'llm/utils.py' adding 'llm/default_plugins/__init__.py' adding 'llm/default_plugins/default_tools.py' adding 'llm/default_plugins/openai_models.py' adding 'llm-0.34.dist-info/licenses/LICENSE' adding 'llm-0.34.dist-info/METADATA' adding 'llm-0.34.dist-info/WHEEL' adding 'llm-0.34.dist-info/entry_points.txt' adding 'llm-0.34.dist-info/top_level.txt' adding 'llm-0.34.dist-info/RECORD' removing build/bdist.linux-x86_64/wheel Building wheel for llm (pyproject.toml): finished with status 'done' Created wheel for llm: filename=llm-0.34-py3-none-any.whl size=145167 sha256=bd41f126979f08a76f5c514a3ee3a0ce7dad3f98a2fa87a93e57ffe5311a13ef Stored in directory: /builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir/pip-ephem-wheel-cache-ahuc2fug/wheels/0a/96/33/c88d2556e34b5f4adcf73b314ce1e110e7de8919096ff789ed Successfully built llm + pushd docs ~/build/BUILD/python-llm-0.34-build/llm-0.34/docs ~/build/BUILD/python-llm-0.34-build/llm-0.34 + make man html Running Sphinx v9.1.0 /bin/sh: line 1: git: command not found loading translations [en]... done making output directory... done Converting `source_suffix = '.rst'` to `source_suffix = {'.rst': 'restructuredtext'}`. myst v5.1.0: MdParserConfig(commonmark_only=False, gfm_only=False, enable_extensions={'colon_fence'}, disable_syntax=[], all_links_external=False, links_external_new_tab=False, url_schemes=('http', 'https', 'mailto', 'ftp'), ref_domains=None, fence_as_directive=set(), number_code_blocks=[], title_to_header=False, heading_anchors=0, heading_slug_func=None, html_meta={}, footnote_sort=True, footnote_transition=True, words_per_minute=200, substitutions={}, linkify_fuzzy_links=True, dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes='tex2jax_process|mathjax_process|math|output_area', enable_checkboxes=False, strikethrough_single_tilde=False, colon_fence_exact_match=False, suppress_warnings=[], highlight_code_blocks=True) building [mo]: targets for 0 po files that are out of date writing output... building [man]: all manpages updating environment: [new config] 28 added, 0 changed, 0 removed reading sources... [ 4%] aliases reading sources... [ 7%] changelog reading sources... [ 11%] contributing reading sources... [ 14%] embeddings/cli reading sources... [ 18%] embeddings/index reading sources... [ 21%] embeddings/python-api reading sources... [ 25%] embeddings/storage reading sources... [ 29%] embeddings/writing-plugins reading sources... [ 32%] fragments reading sources... [ 36%] help reading sources... [ 39%] index reading sources... [ 43%] logging reading sources... [ 46%] openai-models reading sources... [ 50%] other-models reading sources... [ 54%] plugins/advanced-model-plugins reading sources... [ 57%] plugins/directory reading sources... [ 61%] plugins/index reading sources... [ 64%] plugins/installing-plugins reading sources... [ 68%] plugins/plugin-hooks reading sources... [ 71%] plugins/plugin-utilities reading sources... [ 75%] plugins/tutorial-model-plugin reading sources... [ 79%] python-api reading sources... [ 82%] related-tools reading sources... [ 86%] schemas reading sources... [ 89%] setup reading sources... [ 93%] templates reading sources... [ 96%] tools reading sources... [100%] usage looking for now-outdated files... none found pickling environment... done checking consistency... done preparing documents... done copying assets... copying assets: done writing... llm.1 { setup usage openai-models other-models tools schemas templates fragments aliases embeddings/index embeddings/cli embeddings/python-api embeddings/writing-plugins embeddings/storage plugins/index plugins/installing-plugins plugins/directory plugins/plugin-hooks plugins/tutorial-model-plugin plugins/advanced-model-plugins plugins/plugin-utilities python-api logging related-tools help contributing changelog } done build succeeded. The manual pages are in _build/man. Running Sphinx v9.1.0 /bin/sh: line 1: git: command not found loading translations [en]... done making output directory... done Converting `source_suffix = '.rst'` to `source_suffix = {'.rst': 'restructuredtext'}`. loading pickled environment... The configuration has changed (1 option: 'html_static_path') done myst v5.1.0: MdParserConfig(commonmark_only=False, gfm_only=False, enable_extensions={'colon_fence'}, disable_syntax=[], all_links_external=False, links_external_new_tab=False, url_schemes=('http', 'https', 'mailto', 'ftp'), ref_domains=None, fence_as_directive=set(), number_code_blocks=[], title_to_header=False, heading_anchors=0, heading_slug_func=None, html_meta={}, footnote_sort=True, footnote_transition=True, words_per_minute=200, substitutions={}, linkify_fuzzy_links=True, dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes='tex2jax_process|mathjax_process|math|output_area', enable_checkboxes=False, strikethrough_single_tilde=False, colon_fence_exact_match=False, suppress_warnings=[], highlight_code_blocks=True) building [mo]: targets for 0 po files that are out of date writing output... building [html]: targets for 28 source files that are out of date updating environment: 0 added, 0 changed, 0 removed reading sources... looking for now-outdated files... none found preparing documents... done copying assets... copying static files... Writing evaluated template result to /builddir/build/BUILD/python-llm-0.34-build/llm-0.34/docs/_build/html/_static/language_data.js Writing evaluated template result to /builddir/build/BUILD/python-llm-0.34-build/llm-0.34/docs/_build/html/_static/documentation_options.js Writing evaluated template result to /builddir/build/BUILD/python-llm-0.34-build/llm-0.34/docs/_build/html/_static/basic.css Writing evaluated template result to /builddir/build/BUILD/python-llm-0.34-build/llm-0.34/docs/_build/html/_static/copybutton.js copying static files: done copying extra files... copying extra files: done copying assets: done writing output... [ 4%] aliases writing output... [ 7%] changelog writing output... [ 11%] contributing writing output... [ 14%] embeddings/cli writing output... [ 18%] embeddings/index writing output... [ 21%] embeddings/python-api writing output... [ 25%] embeddings/storage writing output... [ 29%] embeddings/writing-plugins writing output... [ 32%] fragments writing output... [ 36%] help writing output... [ 39%] index writing output... [ 43%] logging writing output... [ 46%] openai-models writing output... [ 50%] other-models writing output... [ 54%] plugins/advanced-model-plugins writing output... [ 57%] plugins/directory writing output... [ 61%] plugins/index writing output... [ 64%] plugins/installing-plugins writing output... [ 68%] plugins/plugin-hooks writing output... [ 71%] plugins/plugin-utilities writing output... [ 75%] plugins/tutorial-model-plugin writing output... [ 79%] python-api writing output... [ 82%] related-tools writing output... [ 86%] schemas writing output... [ 89%] setup writing output... [ 93%] templates writing output... [ 96%] tools writing output... [100%] usage generating indices... genindex done writing additional pages... search done dumping search index in English (code: en)... done dumping object inventory... done build succeeded. The HTML pages are in _build/html. + rm -rf docs/_build/html/.buildinfo + find docs/_build/html -size 0 -delete + RPM_EC=0 ++ jobs -p + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.TWBwLS + umask 022 + cd /builddir/build/BUILD/python-llm-0.34-build + '[' /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT '!=' / ']' + rm -rf /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT ++ dirname /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT + mkdir -p /builddir/build/BUILD/python-llm-0.34-build + mkdir /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT + CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + export CFLAGS + CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + export CXXFLAGS + FFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + export FFLAGS + FCFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + export FCFLAGS + VALAFLAGS=-g + export VALAFLAGS + RUSTFLAGS='-Copt-level=3 -Cdebuginfo=2 -Ccodegen-units=1 -Cstrip=none -Cforce-frame-pointers=yes -Clink-arg=-specs=/usr/lib/rpm/redhat/redhat-package-notes --cap-lints=warn' + export RUSTFLAGS + LDFLAGS='-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes ' + export LDFLAGS + LT_SYS_LIBRARY_PATH=/usr/lib64: + export LT_SYS_LIBRARY_PATH + CC=gcc + export CC + CXX=g++ + export CXX + cd llm-0.34 ++ ls /builddir/build/BUILD/python-llm-0.34-build/pyproject-wheeldir/llm-0.34-py3-none-any.whl ++ xargs basename --multiple ++ sed -E 's/([^-]+)-([^-]+)-.+\.whl/\1==\2/' + specifier=llm==0.34 + '[' -z llm==0.34 ']' + PIP_CONFIG_FILE=/dev/null + TMPDIR=/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir + /usr/bin/python3 -m pip install --root /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT --prefix /usr --no-deps --disable-pip-version-check --progress-bar off --verbose --ignore-installed --no-warn-script-location --no-index --no-cache-dir --find-links /builddir/build/BUILD/python-llm-0.34-build/pyproject-wheeldir llm==0.34 Using pip 26.2.1 from /usr/lib/python3.15/site-packages/pip (python 3.15) Looking in links: /builddir/build/BUILD/python-llm-0.34-build/pyproject-wheeldir Processing /builddir/build/BUILD/python-llm-0.34-build/pyproject-wheeldir/llm-0.34-py3-none-any.whl Installing collected packages: llm Creating /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/bin changing mode of /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/bin/llm to 755 Successfully installed llm-0.34 + '[' -d /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/bin ']' + '[' -z sP ']' + shebang_flags=-kasP + /usr/bin/python3 -B /usr/lib/rpm/redhat/pathfix.py -pni /usr/bin/python3 -kasP /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/bin/llm /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/bin/llm: updating + rm -rfv /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/bin/__pycache__ + rm -f /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-ghost-distinfo + site_dirs=() + '[' -d /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages ']' + site_dirs+=("/usr/lib/python3.15/site-packages") + '[' /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib64/python3.15/site-packages '!=' /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages ']' + '[' -d /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib64/python3.15/site-packages ']' + for site_dir in ${site_dirs[@]} + for distinfo in /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT$site_dir/*.dist-info + echo '%ghost %dir /usr/lib/python3.15/site-packages/llm-0.34.dist-info' +++ basename /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm-0.34.dist-info ++ PYTHONPATH=/usr/lib/rpm/redhat ++ /usr/bin/python3 -sBc 'import sys; from pyproject_save_files import canonical_name_from_distinfo; print(canonical_name_from_distinfo(sys.argv[1]))' llm-0.34.dist-info + _normalized=llm + echo '%ghost %dir /usr/lib/python3.15/site-packages/llm-0.34.dist-info' + sed -i s/pip/rpm/ /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm-0.34.dist-info/INSTALLER + PYTHONPATH=/usr/lib/rpm/redhat + /usr/bin/python3 -B /usr/lib/rpm/redhat/pyproject_preprocess_record.py --buildroot /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT --record /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm-0.34.dist-info/RECORD --output /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-record + rm -fv /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm-0.34.dist-info/RECORD removed '/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm-0.34.dist-info/RECORD' + rm -fv /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm-0.34.dist-info/REQUESTED removed '/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm-0.34.dist-info/REQUESTED' + '[' -f /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-dep-overrides ']' ++ wc -l /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-ghost-distinfo ++ cut -f1 '-d ' + lines=1 + '[' 1 -ne 1 ']' + RPM_FILES_ESCAPE=4.19 + /usr/bin/python3 /usr/lib/rpm/redhat/pyproject_save_files.py --output-files /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-files --output-modules /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-modules --buildroot /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT --sitelib /usr/lib/python3.15/site-packages --sitearch /usr/lib64/python3.15/site-packages --python-version 3.15 --pyproject-record /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-record --prefix /usr llm + install -D -m0644 docs/_build/man/llm.1 /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/share/man/man1/llm.1 + /usr/lib/rpm/check-buildroot + /usr/lib/rpm/redhat/brp-ldconfig + COMPRESS='gzip -9 -n' + COMPRESS_EXT=.gz + /usr/lib/rpm/brp-compress + /usr/lib/rpm/brp-strip /usr/bin/strip + /usr/lib/rpm/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump + /usr/lib/rpm/redhat/brp-strip-lto /usr/bin/strip + /usr/lib/rpm/check-rpaths + /usr/lib/rpm/redhat/brp-mangle-shebangs + /usr/lib/rpm/brp-remove-la-files + /usr/lib/rpm/redhat/brp-python-rpm-in-distinfo + env /usr/lib/rpm/redhat/brp-python-bytecompile '' 1 0 -j4 Bytecompiling .py files below /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15 using python3.15 + /usr/lib/rpm/redhat/brp-python-hardlink + /usr/bin/add-det --brp -j4 /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/plugins.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/parts.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/embeddings_migrations.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/utils.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/tools.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/templates.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/embeddings.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/serialization.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/migrations.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/cli.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/__main__.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/logs.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/hookspecs.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/errors.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/__init__.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/__pycache__/__init__.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/__pycache__/default_tools.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/models.cpython-315.opt-1.pyc: replacing with normalized version /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/__pycache__/openai_models.cpython-315.opt-1.pyc: rewriting with normalized contents /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages/llm/__pycache__/models.cpython-315.pyc: replacing with normalized version Scanned 15 directories and 66 files, processed 21 inodes, 20 modified (2 replaced + 18 rewritten), 0 unsupported format, 0 errors + /usr/bin/linkdupes --brp /builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr Scanned 14 directories and 66 files, considered 66 files, read 2 files, linked 1 files, 0 errors sum of sizes of linked files: 0 bytes Executing(%check): /bin/sh -e /var/tmp/rpm-tmp.rpvEvt + umask 022 + cd /builddir/build/BUILD/python-llm-0.34-build + CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + export CFLAGS + CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + export CXXFLAGS + FFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + export FFLAGS + FCFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -I/usr/lib64/gfortran/modules ' + export FCFLAGS + VALAFLAGS=-g + export VALAFLAGS + RUSTFLAGS='-Copt-level=3 -Cdebuginfo=2 -Ccodegen-units=1 -Cstrip=none -Cforce-frame-pointers=yes -Clink-arg=-specs=/usr/lib/rpm/redhat/redhat-package-notes --cap-lints=warn' + export RUSTFLAGS + LDFLAGS='-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes ' + export LDFLAGS + LT_SYS_LIBRARY_PATH=/usr/lib64: + export LT_SYS_LIBRARY_PATH + CC=gcc + export CC + CXX=g++ + export CXX + cd llm-0.34 + '[' '!' -f /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-modules ']' + PATH=/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin + PYTHONPATH=/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib64/python3.15/site-packages:/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages + _PYTHONSITE=/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib64/python3.15/site-packages:/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages + PYTHONDONTWRITEBYTECODE=1 + /usr/bin/python3 -sP /usr/lib/rpm/redhat/import_all_modules.py -f /builddir/build/BUILD/python-llm-0.34-build/python-llm-0.34-1.fc46.x86_64-pyproject-modules Check import: llm Check import: llm.cli Check import: llm.default_plugins Check import: llm.default_plugins.default_tools Check import: llm.default_plugins.openai_models Check import: llm.embeddings Check import: llm.embeddings_migrations Check import: llm.errors Check import: llm.hookspecs Check import: llm.logs Check import: llm.migrations Check import: llm.models Check import: llm.parts Check import: llm.plugins Check import: llm.serialization Check import: llm.templates Check import: llm.tools Check import: llm.utils + export ISOLATED_CI_ENV=1 + ISOLATED_CI_ENV=1 + CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer ' + LDFLAGS='-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes ' + PATH=/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin + PYTHONPATH=/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib64/python3.15/site-packages:/builddir/build/BUILD/python-llm-0.34-build/BUILDROOT/usr/lib/python3.15/site-packages + PYTHONDONTWRITEBYTECODE=1 + PYTEST_ADDOPTS=' --ignore=/builddir/build/BUILD/python-llm-0.34-build/.pyproject-builddir' + PYTEST_XDIST_AUTO_NUM_WORKERS=4 + /usr/bin/pytest ============================= test session starts ============================== platform linux -- Python 3.15.0, pytest-9.1.1, pluggy-1.6.0 SQLite: 3.53.4 sqlite-utils: 4.2.1 rootdir: /builddir/build/BUILD/python-llm-0.34-build/llm-0.34 configfile: pytest.ini plugins: httpx-0.36.0, asyncio-1.4.0, recording-0.14.0, anyio-4.15.1 asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function collected 1124 items tests/test_aliases.py ................. [ 1%] tests/test_async.py .... [ 1%] tests/test_async_parity.py ................. [ 3%] tests/test_attachments.py ...ssss...... [ 4%] tests/test_chat.py .......... [ 5%] tests/test_chat_templates.py ... [ 5%] tests/test_cli_openai_models.py s........................FEFE.FEFEFE.... [ 8%] ..FEFEFE.FEFEFEFEFEFE [ 9%] tests/test_cli_options.py ...... [ 10%] tests/test_cli_streaming.py ........ [ 11%] tests/test_embed.py .................... [ 12%] tests/test_embed_cli.py ................................................ [ 17%] .............................................. [ 21%] tests/test_encode_decode.py .. [ 21%] tests/test_fragments_cli.py ...s [ 21%] tests/test_keys.py ......FE [ 22%] tests/test_llm.py .FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEF [ 24%] EFEFEFEFE.FEFEFE..................................FEFE........ [ 29%] tests/test_llm_logs.py ................................................. [ 33%] ...................sss.sss............ [ 37%] tests/test_logs_store.py ............................................... [ 41%] ........................................................................ [ 47%] .............................................. [ 51%] tests/test_migrate.py ...... [ 52%] tests/test_openai_endpoint.py FEFEFEFEFEFE.FEFEFEFEFEFEFEFEFEFE.FEFEFEFE [ 54%] FEFEFE [ 54%] tests/test_openai_messages.py .............FEFEFEFEFEFEFEFEFEFEFE [ 56%] tests/test_openai_responses.py ..................FE.FEFE..FEFE.FEFEFEFE. [ 59%] .FE................FEFEFE......FEFEFEFEFE. [ 62%] tests/test_options_parameter.py ......... [ 63%] tests/test_parts.py .................................................... [ 68%] ........................................................................ [ 74%] ....................... [ 76%] tests/test_pause_resume.py .............. [ 77%] tests/test_plugins.py ..s........ [ 78%] tests/test_serialization.py ............................................ [ 82%] ....... [ 83%] tests/test_templates.py .........................sssssssssssFEsss.FEssss [ 87%] [ 87%] tests/test_tools.py ..........ss................................... [ 91%] tests/test_tools_streaming.py ssss [ 91%] tests/test_utils.py .................................................... [ 96%] ....................................... [100%] ==================================== ERRORS ==================================== _ ERROR at teardown of test_gpt5_verbosity_option_is_sent_to_openai_chat_completions _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414dbb2820> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_gpt5_verbosity_option_is_sent_to_openai_responses_by_default _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c378de0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_code_interpreter_cli_tool_is_resolved_from_model __ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414bb28980> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_code_interpreter_cli_tool_is_reused_on_continue ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd29080> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _____ ERROR at teardown of test_web_search_cli_tool_is_resolved_from_model _____ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d112660> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_openai_image_detail_option_is_sent_on_image_attachments _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd14d00> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_openai_image_detail_original_is_sent_for_gpt54 ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd649f0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_openai_image_detail_original_is_sent_for_gpt54_responses_by_default _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd52270> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _______ ERROR at teardown of test_gpt4o_mini_sync_and_async[None-False] ________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd35860> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ________ ERROR at teardown of test_gpt4o_mini_sync_and_async[None-True] ________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be679a0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ________ ERROR at teardown of test_gpt4o_mini_sync_and_async[-u-False] _________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cef6eb0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _________ ERROR at teardown of test_gpt4o_mini_sync_and_async[-u-True] _________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd7be00> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_gpt4o_mini_sync_and_async[--usage-False] ______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd526d0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_gpt4o_mini_sync_and_async[--usage-True] _______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be31550> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __________________ ERROR at teardown of test_uses_correct_key __________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be90f30> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _______ ERROR at teardown of test_llm_prompt_creates_log_database[False] _______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cf22200> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _______ ERROR at teardown of test_llm_prompt_creates_log_database[True] ________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be918d0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_llm_default_prompt[True-logs_args0-False-True] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b8b2cf0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[True-logs_args0-False-False] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cf014e0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[True-logs_args0-False-split] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cebcd70> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_llm_default_prompt[False-logs_args1-True-True] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cebe820> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[False-logs_args1-True-False] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b973380> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[False-logs_args1-True-split] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be30050> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[False-logs_args2-False-True] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414ce9c210> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[False-logs_args2-False-False] __ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414ce9ad60> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[False-logs_args2-False-split] __ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cecd320> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_llm_default_prompt[False-logs_args3-True-True] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cefc750> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[False-logs_args3-True-False] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c87d2b0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[False-logs_args3-True-split] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cefe4a0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_llm_default_prompt[True-logs_args4-False-True] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cec03d0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[True-logs_args4-False-False] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c820ad0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_llm_default_prompt[True-logs_args4-False-split] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414ceb0d00> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_llm_default_prompt[True-logs_args5-True-True] ____ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c4d9fd0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_llm_default_prompt[True-logs_args5-True-False] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c5a3850> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_llm_default_prompt[True-logs_args5-True-split] ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c4b8ad0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _____________ ERROR at teardown of test_llm_prompt_continue[False] _____________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c538050> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _____________ ERROR at teardown of test_llm_prompt_continue[True] ______________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be5ed60> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __________ ERROR at teardown of test_extract_fenced_code[args0-True] ___________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c5a07c0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __________ ERROR at teardown of test_extract_fenced_code[args1-True] ___________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cefe4a0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __________ ERROR at teardown of test_extract_fenced_code[args2-True] ___________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c58c600> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __________ ERROR at teardown of test_extract_fenced_code[args3-True] ___________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c4d27b0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __________ ERROR at teardown of test_extract_fenced_code[args4-False] __________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c50fee0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______________ ERROR at teardown of test_extract_fenced_code_crlf ______________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c574c90> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _________________ ERROR at teardown of test_openai_chat_stream _________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c4c2f90> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _________________ ERROR at teardown of test_openai_completion __________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c4c0130> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ____ ERROR at teardown of test_openai_completion_continue_includes_history _____ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414bb8b9a0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _________ ERROR at teardown of test_openai_completion_logprobs_stream __________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414bb1d400> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ________ ERROR at teardown of test_openai_completion_logprobs_nostream _________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c53a190> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ____________ ERROR at teardown of test_openai_localai_configuration ____________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c576510> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on http://localai.localhost/chat/completions E - Match POST request on http://localai.localhost/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_llm_prompt_continue_with_database[False] ______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be5ecf0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_llm_prompt_continue_with_database[True] _______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414baecf30> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_endpoint_chat_completions_does_not_log_or_leak_default_key _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c82a040> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ________ ERROR at teardown of test_endpoint_chat_completions_attachment ________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c7c1550> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://attachments.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _________________ ERROR at teardown of test_endpoint_template __________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c7c4e50> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://templates.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_endpoint_template_schema_object_used_when_no_cli_schema _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be5ed60> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://templates2.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __________________ ERROR at teardown of test_endpoint_schema ___________________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414bb126d0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://schema.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_endpoint_schema_by_id_from_existing_logs_database __ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d162e40> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://schema-id.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_endpoint_static_template_runs_once_on_terminal ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d498e50> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://terminal-template.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ____________ ERROR at teardown of test_endpoint_tools_and_functions ____________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d4d9470> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://tools.example.test/v1/chat/completions E - Match POST request on https://tools.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ____________ ERROR at teardown of test_endpoint_streams_by_default _____________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d4d9e80> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://stream.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _____________ ERROR at teardown of test_endpoint_uses_explicit_key _____________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d194b40> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_endpoint_lists_models_without_model_or_logging ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c829550> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match GET request on https://models.example.test/v1/models E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_endpoint_models_surfaces_error_from_successful_response _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d510210> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match GET request on https://models-error.example.test/models E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _______________ ERROR at teardown of test_endpoint_responses_api _______________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d50a270> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://responses.example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_endpoint_responses_reasoning_summary_option[auto] __ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d497d20> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://responses-summary.example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_endpoint_responses_reasoning_summary_option[concise] _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d4a8600> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://responses-summary.example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_endpoint_responses_reasoning_summary_option[detailed] _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d460b40> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://responses-summary.example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _________ ERROR at teardown of test_endpoint_responses_api_attachment __________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d48fb60> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://responses-attachments.example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ________ ERROR at teardown of test_endpoint_responses_api_schema_multi _________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f4149ab9550> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://responses-schema.example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ____________ ERROR at teardown of test_endpoint_responses_api_tools ____________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d494050> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://responses-tools.example.test/v1/responses E - Match POST request on https://responses-tools.example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ____ ERROR at teardown of test_endpoint_responses_api_raw_server_side_tool _____ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d4db4d0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://raw-tools.example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_endpoint_reads_one_off_prompt_from_stdin ______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f4149b80910> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://stdin.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_endpoint_without_prompt_waits_for_stdin _______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f4149b5d6a0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://terminal-stdin.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ____ ERROR at teardown of test_endpoint_interactive_chat_preserves_history _____ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f4149b44280> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://chat.example.test/v1/chat/completions E - Match POST request on https://chat.example.test/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestBuildMessagesConversationHistory.test_no_double_emission_from_conversation_prompt_flow _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f4149aabf50> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestStreamingExecuteYieldsStreamEvents.test_text_stream_yields_text_events _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c23e200> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestStreamingExecuteYieldsStreamEvents.test_text_stream_plain_iteration_still_returns_strings _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c221a90> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestStreamingExecuteYieldsStreamEvents.test_text_stream_messages_assembled _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c223ee0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestStreamingExecuteYieldsStreamEvents.test_tool_call_stream_yields_name_and_args_events _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c278b40> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestStreamingExecuteYieldsStreamEvents.test_tool_call_registered_via_add_tool_call _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f4149b47310> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestStreamingExecuteYieldsStreamEvents.test_text_then_tool_call_part_index_advances _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f4149b182f0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestAsyncStreamingExecuteYieldsStreamEvents.test_text_stream_yields_text_events _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c1ec1a0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestReasoningTokenCount.test_redacted_reasoning_part_emitted_when_count_present _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c1b0590> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestReasoningTokenCount.test_no_reasoning_part_when_zero_or_absent _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c1d1c50> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of TestNonStreamingExecuteYieldsStreamEvents.test_non_streaming_text_yields_single_event _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c2a1a20> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_responses_web_search_request_and_result_capture ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c1d5080> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_responses_mixes_function_and_code_interpreter_tools _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c3175b0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_responses_raw_server_tool_passthrough_on_custom_endpoint _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c387070> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://example.test/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_async_responses_code_interpreter_request ______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c303620> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _________ ERROR at teardown of test_async_responses_web_search_request _________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c1d2cf0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ____ ERROR at teardown of test_chat_completions_opt_out_dispatches_to_chat _____ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c316350> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ________ ERROR at teardown of test_default_routes_to_responses_endpoint ________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c39da90> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_hide_reasoning_omits_reasoning_summary_from_responses_request _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c2c92b0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_non_reasoning_responses_model_omits_encrypted_reasoning_include _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c2d0de0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_responses_reply_sends_prior_assistant_text_as_string _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c2cbd20> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_service_tier_sent_to_responses_endpoint _______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b4434d0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_service_tier_sent_to_chat_completions_fallback ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b491780> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_responses_streams_reasoning_summary_text ______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b444980> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_responses_reasoning_metadata_refreshed_from_final_payload _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cae9b70> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ______ ERROR at teardown of test_code_interpreter_multi_message_response _______ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b8614e0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError ___ ERROR at teardown of test_code_interpreter_streaming_output_and_request ____ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b7fd240> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_web_search_streaming_refreshes_from_final_payload __ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b7b0a60> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _ ERROR at teardown of test_async_web_search_streaming_refreshes_from_final_payload _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414b83c2f0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/responses E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError __ ERROR at teardown of test_execute_prompt_with_multiple_templates_in_order ___ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d42f8c0> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError _________ ERROR at teardown of test_template_respects_cli_extract_flag _________ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f41497ad470> request = > @pytest.fixture def httpx_mock( monkeypatch: MonkeyPatch, request: FixtureRequest, ) -> Generator[HTTPXMock, None, None]: options = {} for marker in request.node.iter_markers("httpx_mock"): options = marker.kwargs | options __tracebackhide__ = methodcaller("errisinstance", TypeError) options = _HTTPXMockOptions(**options) mock = HTTPXMock(options) # Mock synchronous requests real_handle_request = httpx.HTTPTransport.handle_request def mocked_handle_request( transport: httpx.HTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return mock._handle_request(transport, request) return real_handle_request(transport, request) monkeypatch.setattr( httpx.HTTPTransport, "handle_request", mocked_handle_request, ) # Mock asynchronous requests real_handle_async_request = httpx.AsyncHTTPTransport.handle_async_request async def mocked_handle_async_request( transport: httpx.AsyncHTTPTransport, request: httpx.Request ) -> httpx.Response: if options.should_mock(request): return await mock._handle_async_request(transport, request) return await real_handle_async_request(transport, request) monkeypatch.setattr( httpx.AsyncHTTPTransport, "handle_async_request", mocked_handle_async_request, ) yield mock try: > mock._assert_options() /usr/lib/python3.15/site-packages/pytest_httpx/__init__.py:67: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = def _assert_options(self) -> None: callbacks_not_executed = [ matcher for matcher, _ in self._callbacks if matcher.should_have_matched() ] matchers_description = "\n".join( [f"- {matcher}" for matcher in callbacks_not_executed] ) > assert not callbacks_not_executed, ( ^^^^^^^^^^^^^^^^^^^^^^^^^^ "The following responses are mocked but not requested:\n" f"{matchers_description}\n" "\n" "If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested" ) E AssertionError: The following responses are mocked but not requested: E - Match POST request on https://api.openai.com/v1/chat/completions E E If this is on purpose, refer to https://github.com/Colin-b/pytest_httpx/blob/master/README.md#allow-to-register-more-responses-than-what-will-be-requested /usr/lib/python3.15/site-packages/pytest_httpx/_httpx_mock.py:325: AssertionError =================================== FAILURES =================================== ________ test_gpt5_verbosity_option_is_sent_to_openai_chat_completions _________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...alse, 'messages': [{'role': 'user', 'content': 'Say hi'}], 'verbosity': }, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_gpt5_verbosity_option_is_sent_to_openai_chat_completions(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "model": "gpt-5", "usage": {}, "choices": [{"message": {"content": "Verbose enough"}}], }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() > result = runner.invoke( cli, [ "-m", "gpt-5", "-o", "chat_completions", "1", "-o", "verbosity", "high", "--no-stream", "--key", "x", "Say hi", ], catch_exceptions=False, ) tests/test_cli_openai_models.py:133: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2493: in execute yield from chat.execute(prompt, stream, response, conversation, key) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...alse, 'messages': [{'role': 'user', 'content': 'Say hi'}], 'verbosity': }, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ______ test_gpt5_verbosity_option_is_sent_to_openai_responses_by_default _______ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...reasoning': {'summary': 'auto'}, 'store': False, 'text': {'verbosity': }}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_gpt5_verbosity_option_is_sent_to_openai_responses_by_default(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_test_1", "object": "response", "created_at": 1, "model": "gpt-5", "output": [ { "type": "message", "id": "msg_1", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "Verbose enough", "annotations": [], } ], } ], "usage": { "input_tokens": 5, "output_tokens": 3, "total_tokens": 8, }, "status": "completed", }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() > result = runner.invoke( cli, [ "-m", "gpt-5", "-o", "verbosity", "high", "--no-stream", "--key", "x", "Say hi", ], catch_exceptions=False, ) tests/test_cli_openai_models.py:191: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...reasoning': {'summary': 'auto'}, 'store': False, 'text': {'verbosity': }}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________ test_code_interpreter_cli_tool_is_resolved_from_model _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_... False, 'tools': [{'type': 'code_interpreter', 'container': {'type': 'auto', 'memory_limit': '4g'}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_code_interpreter_cli_tool_is_resolved_from_model(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_code_interpreter_cli", "object": "response", "created_at": 1, "model": "gpt-5.6-luna", "output": [ { "type": "message", "id": "msg_code_interpreter_cli", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "Calculated", "annotations": [], } ], } ], "usage": {"input_tokens": 1, "output_tokens": 1, "total_tokens": 2}, "status": "completed", }, headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "-m", "gpt-5.6-luna", "-T", 'CodeInterpreter(memory_limit="4g")', "--no-stream", "--no-log", "--key", "x", "Run this calculation", ], catch_exceptions=False, ) tests/test_cli_openai_models.py:252: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:3032: in text return "".join(self) ^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2995: in __iter__ for chunk in response_item: ^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_... False, 'tools': [{'type': 'code_interpreter', 'container': {'type': 'auto', 'memory_limit': '4g'}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_code_interpreter_cli_tool_is_reused_on_continue _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_... False, 'tools': [{'type': 'code_interpreter', 'container': {'type': 'auto', 'memory_limit': '4g'}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_code_interpreter_cli_tool1/llm.datasette.io') def test_code_interpreter_cli_tool_is_reused_on_continue(httpx_mock, user_path): def response_payload(response_id, text): return { "id": response_id, "object": "response", "created_at": 1, "model": "gpt-5.6-luna", "output": [ { "type": "message", "id": f"msg_{response_id}", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": text, "annotations": [], } ], } ], "usage": {"input_tokens": 1, "output_tokens": 1, "total_tokens": 2}, "status": "completed", } first_payload = response_payload("resp_code_interpreter_first", "Calculated") first_payload["output"] = [ { "type": "message", "id": "msg_before_code", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "Running Python", "annotations": [], } ], }, { "type": "code_interpreter_call", "id": "ci_continue", "status": "completed", "container_id": "cntr_continue", "code": "print(6 * 7)", "outputs": [{"type": "logs", "logs": "42\n"}], }, { "type": "message", "id": "msg_after_code", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "Calculated", "annotations": [], } ], }, ] for payload in ( first_payload, response_payload("resp_code_interpreter_second", "Continued"), ): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json=payload, headers={"Content-Type": "application/json"}, ) runner = CliRunner() > first = runner.invoke( cli, [ "-m", "gpt-5.6-luna", "-T", 'CodeInterpreter(memory_limit="4g")', "--no-stream", "--key", "x", "Run this calculation", ], catch_exceptions=False, ) tests/test_cli_openai_models.py:355: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:3032: in text return "".join(self) ^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2995: in __iter__ for chunk in response_item: ^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_... False, 'tools': [{'type': 'code_interpreter', 'container': {'type': 'auto', 'memory_limit': '4g'}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _______________ test_web_search_cli_tool_is_resolved_from_model ________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...'type': 'web_search', 'filters': {'allowed_domains': ['openai.com']}, 'search_context_size': 'low'}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_web_search_cli_tool_is_resolved_from_model(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_web_search_cli", "object": "response", "created_at": 1, "model": "gpt-5.6-luna", "output": [ { "type": "message", "id": "msg_web_search_cli", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "Search complete", "annotations": [], } ], } ], "usage": {"input_tokens": 1, "output_tokens": 1, "total_tokens": 2}, "status": "completed", }, headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "-m", "gpt-5.6-luna", "-T", 'WebSearch(allowed_domains=["openai.com"], search_context_size="low", include_sources=true)', "--no-stream", "--no-log", "--key", "x", "Search for OpenAI news", ], catch_exceptions=False, ) tests/test_cli_openai_models.py:430: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:3032: in text return "".join(self) ^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2995: in __iter__ for chunk in response_item: ^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...'type': 'web_search', 'filters': {'allowed_domains': ['openai.com']}, 'search_context_size': 'low'}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________ test_openai_image_detail_option_is_sent_on_image_attachments _________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...}, {'type': 'image_url', 'image_url': {'url': 'https://example.com/image.jpg', 'detail': 'high'}}]}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_openai_image_detail_option_is_sent_on_image_attachments(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "model": "gpt-4o", "usage": {}, "choices": [{"message": {"content": "Looks detailed"}}], }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() > result = runner.invoke( cli, [ "-m", "gpt-4o", "-o", "image_detail", "high", "--at", "https://example.com/image.jpg", "image/jpeg", "--no-stream", "--key", "x", "Describe this", ], catch_exceptions=False, ) tests/test_cli_openai_models.py:543: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...}, {'type': 'image_url', 'image_url': {'url': 'https://example.com/image.jpg', 'detail': 'high'}}]}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_openai_image_detail_original_is_sent_for_gpt54 ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...'type': 'image_url', 'image_url': {'url': 'https://example.com/image.jpg', 'detail': 'original'}}]}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_openai_image_detail_original_is_sent_for_gpt54(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "model": "gpt-5.4", "usage": {}, "choices": [{"message": {"content": "Original detail"}}], }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() > result = runner.invoke( cli, [ "-m", "gpt-5.4", "-o", "chat_completions", "1", "-o", "image_detail", "original", "--at", "https://example.com/image.jpg", "image/jpeg", "--no-stream", "--key", "x", "Describe this", ], catch_exceptions=False, ) tests/test_cli_openai_models.py:586: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2493: in execute yield from chat.execute(prompt, stream, response, conversation, key) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...'type': 'image_url', 'image_url': {'url': 'https://example.com/image.jpg', 'detail': 'original'}}]}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ___ test_openai_image_detail_original_is_sent_for_gpt54_responses_by_default ___ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...//example.com/image.jpg', 'detail': 'original'}]}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_openai_image_detail_original_is_sent_for_gpt54_responses_by_default( httpx_mock, ): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_test_1", "object": "response", "created_at": 1, "model": "gpt-5.4", "output": [ { "type": "message", "id": "msg_1", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "Original detail", "annotations": [], } ], } ], "usage": { "input_tokens": 5, "output_tokens": 3, "total_tokens": 8, }, "status": "completed", }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() > result = runner.invoke( cli, [ "-m", "gpt-5.4", "-o", "image_detail", "original", "--at", "https://example.com/image.jpg", "image/jpeg", "--no-stream", "--key", "x", "Describe this", ], catch_exceptions=False, ) tests/test_cli_openai_models.py:649: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...//example.com/image.jpg', 'detail': 'original'}]}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __________________ test_gpt4o_mini_sync_and_async[None-False] __________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd35860> tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_gpt4o_mini_sync_and_async0') httpx_mock = async_ = False, usage = None @pytest.mark.parametrize("async_", (False, True)) @pytest.mark.parametrize("usage", (None, "-u", "--usage")) def test_gpt4o_mini_sync_and_async(monkeypatch, tmpdir, httpx_mock, async_, usage): user_path = tmpdir / "user_dir" log_db = user_path / "logs.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) assert not log_db.exists() httpx_mock.add_response( method="POST", # chat completion request url="https://api.openai.com/v1/chat/completions", json={ "id": "chatcmpl-AQT9a30kxEaM1bqxRPepQsPlCyGJh", "object": "chat.completion", "created": 1730871958, "model": "gpt-4o-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Ho ho ho", "refusal": None, }, "finish_reason": "stop", } ], "usage": { "prompt_tokens": 1000, "completion_tokens": 2000, "total_tokens": 12, }, "system_fingerprint": "fp_49254d0e9b", }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() args = ["-m", "gpt-4o-mini", "--key", "x", "--no-stream"] if usage: args.append(usage) if async_: args.append("--async") > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_cli_openai_models.py:730: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __________________ test_gpt4o_mini_sync_and_async[None-True] ___________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be679a0> tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_gpt4o_mini_sync_and_async1') httpx_mock = async_ = True, usage = None @pytest.mark.parametrize("async_", (False, True)) @pytest.mark.parametrize("usage", (None, "-u", "--usage")) def test_gpt4o_mini_sync_and_async(monkeypatch, tmpdir, httpx_mock, async_, usage): user_path = tmpdir / "user_dir" log_db = user_path / "logs.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) assert not log_db.exists() httpx_mock.add_response( method="POST", # chat completion request url="https://api.openai.com/v1/chat/completions", json={ "id": "chatcmpl-AQT9a30kxEaM1bqxRPepQsPlCyGJh", "object": "chat.completion", "created": 1730871958, "model": "gpt-4o-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Ho ho ho", "refusal": None, }, "finish_reason": "stop", } ], "usage": { "prompt_tokens": 1000, "completion_tokens": 2000, "total_tokens": 12, }, "system_fingerprint": "fp_49254d0e9b", }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() args = ["-m", "gpt-4o-mini", "--key", "x", "--no-stream"] if usage: args.append(usage) if async_: args.append("--async") > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_cli_openai_models.py:730: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1116: in prompt response = asyncio.run(inner()) ^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:205: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:128: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/base_events.py:724: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1107: in inner text = await response.text() ^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1575: in execute completion = await client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:2952: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError ___________________ test_gpt4o_mini_sync_and_async[-u-False] ___________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cef6eb0> tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_gpt4o_mini_sync_and_async2') httpx_mock = async_ = False, usage = '-u' @pytest.mark.parametrize("async_", (False, True)) @pytest.mark.parametrize("usage", (None, "-u", "--usage")) def test_gpt4o_mini_sync_and_async(monkeypatch, tmpdir, httpx_mock, async_, usage): user_path = tmpdir / "user_dir" log_db = user_path / "logs.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) assert not log_db.exists() httpx_mock.add_response( method="POST", # chat completion request url="https://api.openai.com/v1/chat/completions", json={ "id": "chatcmpl-AQT9a30kxEaM1bqxRPepQsPlCyGJh", "object": "chat.completion", "created": 1730871958, "model": "gpt-4o-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Ho ho ho", "refusal": None, }, "finish_reason": "stop", } ], "usage": { "prompt_tokens": 1000, "completion_tokens": 2000, "total_tokens": 12, }, "system_fingerprint": "fp_49254d0e9b", }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() args = ["-m", "gpt-4o-mini", "--key", "x", "--no-stream"] if usage: args.append(usage) if async_: args.append("--async") > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_cli_openai_models.py:730: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ___________________ test_gpt4o_mini_sync_and_async[-u-True] ____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd7be00> tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_gpt4o_mini_sync_and_async3') httpx_mock = async_ = True, usage = '-u' @pytest.mark.parametrize("async_", (False, True)) @pytest.mark.parametrize("usage", (None, "-u", "--usage")) def test_gpt4o_mini_sync_and_async(monkeypatch, tmpdir, httpx_mock, async_, usage): user_path = tmpdir / "user_dir" log_db = user_path / "logs.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) assert not log_db.exists() httpx_mock.add_response( method="POST", # chat completion request url="https://api.openai.com/v1/chat/completions", json={ "id": "chatcmpl-AQT9a30kxEaM1bqxRPepQsPlCyGJh", "object": "chat.completion", "created": 1730871958, "model": "gpt-4o-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Ho ho ho", "refusal": None, }, "finish_reason": "stop", } ], "usage": { "prompt_tokens": 1000, "completion_tokens": 2000, "total_tokens": 12, }, "system_fingerprint": "fp_49254d0e9b", }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() args = ["-m", "gpt-4o-mini", "--key", "x", "--no-stream"] if usage: args.append(usage) if async_: args.append("--async") > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_cli_openai_models.py:730: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1116: in prompt response = asyncio.run(inner()) ^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:205: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:128: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/base_events.py:724: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1107: in inner text = await response.text() ^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1575: in execute completion = await client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:2952: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError ________________ test_gpt4o_mini_sync_and_async[--usage-False] _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cd526d0> tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_gpt4o_mini_sync_and_async4') httpx_mock = async_ = False, usage = '--usage' @pytest.mark.parametrize("async_", (False, True)) @pytest.mark.parametrize("usage", (None, "-u", "--usage")) def test_gpt4o_mini_sync_and_async(monkeypatch, tmpdir, httpx_mock, async_, usage): user_path = tmpdir / "user_dir" log_db = user_path / "logs.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) assert not log_db.exists() httpx_mock.add_response( method="POST", # chat completion request url="https://api.openai.com/v1/chat/completions", json={ "id": "chatcmpl-AQT9a30kxEaM1bqxRPepQsPlCyGJh", "object": "chat.completion", "created": 1730871958, "model": "gpt-4o-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Ho ho ho", "refusal": None, }, "finish_reason": "stop", } ], "usage": { "prompt_tokens": 1000, "completion_tokens": 2000, "total_tokens": 12, }, "system_fingerprint": "fp_49254d0e9b", }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() args = ["-m", "gpt-4o-mini", "--key", "x", "--no-stream"] if usage: args.append(usage) if async_: args.append("--async") > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_cli_openai_models.py:730: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________________ test_gpt4o_mini_sync_and_async[--usage-True] _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be31550> tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_gpt4o_mini_sync_and_async5') httpx_mock = async_ = True, usage = '--usage' @pytest.mark.parametrize("async_", (False, True)) @pytest.mark.parametrize("usage", (None, "-u", "--usage")) def test_gpt4o_mini_sync_and_async(monkeypatch, tmpdir, httpx_mock, async_, usage): user_path = tmpdir / "user_dir" log_db = user_path / "logs.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) assert not log_db.exists() httpx_mock.add_response( method="POST", # chat completion request url="https://api.openai.com/v1/chat/completions", json={ "id": "chatcmpl-AQT9a30kxEaM1bqxRPepQsPlCyGJh", "object": "chat.completion", "created": 1730871958, "model": "gpt-4o-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Ho ho ho", "refusal": None, }, "finish_reason": "stop", } ], "usage": { "prompt_tokens": 1000, "completion_tokens": 2000, "total_tokens": 12, }, "system_fingerprint": "fp_49254d0e9b", }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() args = ["-m", "gpt-4o-mini", "--key", "x", "--no-stream"] if usage: args.append(usage) if async_: args.append("--async") > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_cli_openai_models.py:730: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1116: in prompt response = asyncio.run(inner()) ^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:205: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:128: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/base_events.py:724: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1107: in inner text = await response.text() ^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1575: in execute completion = await client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:2952: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...vent_and_data=None, content=None, json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': []}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError ____________________________ test_uses_correct_key _____________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...on_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'hello'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_chat = monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be90f30> tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_uses_correct_key0') @pytest.mark.httpx_mock( assert_all_requests_were_expected=False, can_send_already_matched_responses=True ) def test_uses_correct_key(mocked_openai_chat, monkeypatch, tmpdir): user_dir = tmpdir / "user-dir" pathlib.Path(user_dir).mkdir() keys_path = user_dir / "keys.json" KEYS = { "openai": "from-keys-file", "other": "other-key", } keys_path.write_text(json.dumps(KEYS), "utf-8") monkeypatch.setenv("LLM_USER_PATH", str(user_dir)) monkeypatch.setenv("OPENAI_API_KEY", "from-env") def assert_key(key): request = mocked_openai_chat.get_requests()[-1] assert request.headers["Authorization"] == f"Bearer {key}" runner = CliRunner() # Called without --key uses stored key > result = runner.invoke( cli, ["hello", "--no-stream", "-m", "gpt-4o-mini"], catch_exceptions=False, ) tests/test_keys.py:91: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...on_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'hello'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________________ test_llm_prompt_creates_log_database[False] __________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_prompt_creates_log_da0') monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414cf22200> custom_database_path = False @pytest.mark.parametrize("custom_database_path", (False, True)) def test_llm_prompt_creates_log_database( mocked_openai_responses, tmpdir, monkeypatch, custom_database_path ): user_path = tmpdir / "user" custom_db_path = tmpdir / "custom_log.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) runner = CliRunner() args = ["three names \nfor a pet pelican", "--no-stream", "--key", "x"] if custom_database_path: args.extend(["--database", str(custom_db_path)]) > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:40: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __________________ test_llm_prompt_creates_log_database[True] __________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_prompt_creates_log_da1') monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be918d0> custom_database_path = True @pytest.mark.parametrize("custom_database_path", (False, True)) def test_llm_prompt_creates_log_database( mocked_openai_responses, tmpdir, monkeypatch, custom_database_path ): user_path = tmpdir / "user" custom_db_path = tmpdir / "custom_log.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) runner = CliRunner() args = ["three names \nfor a pet pelican", "--no-stream", "--key", "x"] if custom_database_path: args.extend(["--database", str(custom_db_path)]) > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:40: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[True-logs_args0-False-True] ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = True user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l0/llm.datasette.io') logs_off = True, logs_args = [], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[True-logs_args0-False-False] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = False user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l1/llm.datasette.io') logs_off = True, logs_args = [], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[True-logs_args0-False-split] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = 'split' user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l2/llm.datasette.io') logs_off = True, logs_args = [], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[False-logs_args1-True-True] ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = True user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_0/llm.datasette.io') logs_off = False, logs_args = [], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[False-logs_args1-True-False] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = False user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_1/llm.datasette.io') logs_off = False, logs_args = [], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[False-logs_args1-True-split] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = 'split' user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_2/llm.datasette.io') logs_off = False, logs_args = [], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[False-logs_args2-False-True] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = True user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_3/llm.datasette.io') logs_off = False, logs_args = ['--no-log'], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________ test_llm_default_prompt[False-logs_args2-False-False] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = False user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_4/llm.datasette.io') logs_off = False, logs_args = ['--no-log'], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________ test_llm_default_prompt[False-logs_args2-False-split] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = 'split' user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_5/llm.datasette.io') logs_off = False, logs_args = ['--no-log'], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[False-logs_args3-True-True] ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = True user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_6/llm.datasette.io') logs_off = False, logs_args = ['--log'], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[False-logs_args3-True-False] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = False user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_7/llm.datasette.io') logs_off = False, logs_args = ['--log'], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[False-logs_args3-True-split] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = 'split' user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_False_8/llm.datasette.io') logs_off = False, logs_args = ['--log'], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[True-logs_args4-False-True] ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = True user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l3/llm.datasette.io') logs_off = True, logs_args = ['-n'], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[True-logs_args4-False-False] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = False user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l4/llm.datasette.io') logs_off = True, logs_args = ['-n'], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[True-logs_args4-False-split] _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = 'split' user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l5/llm.datasette.io') logs_off = True, logs_args = ['-n'], should_log = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ______________ test_llm_default_prompt[True-logs_args5-True-True] ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = True user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l6/llm.datasette.io') logs_off = True, logs_args = ['--log'], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[True-logs_args5-True-False] ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = False user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l7/llm.datasette.io') logs_off = True, logs_args = ['--log'], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_llm_default_prompt[True-logs_args5-True-split] ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_responses = use_stdin = 'split' user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_default_prompt_True_l8/llm.datasette.io') logs_off = True, logs_args = ['--log'], should_log = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("use_stdin", (True, False, "split")) @pytest.mark.parametrize( "logs_off,logs_args,should_log", ( (True, [], False), (False, [], True), (False, ["--no-log"], False), (False, ["--log"], True), (True, ["-n"], False), # Short for --no-log (True, ["--log"], True), ), ) def test_llm_default_prompt( mocked_openai_responses, use_stdin, user_path, logs_off, logs_args, should_log ): # Reset the log_path database log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") logs_off_path = user_path / "logs-off" if logs_off: # Turn off logging assert not logs_off_path.exists() CliRunner().invoke(cli, ["logs", "off"]) assert logs_off_path.exists() else: # Turn on logging CliRunner().invoke(cli, ["logs", "on"]) assert not logs_off_path.exists() # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" input = None args = ["--no-stream"] if use_stdin == "split": input = "three names" args.append("\nfor a pet pelican") elif use_stdin: input = prompt else: args.append(prompt) args += logs_args > result = runner.invoke(cli, args, input=input, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _______________________ test_llm_prompt_continue[False] ________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = mock_openai_responses = .add_response at 0x7f414be46c40> user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_prompt_continue_False0/llm.datasette.io') async_ = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("async_", (False, True)) def test_llm_prompt_continue(httpx_mock, mock_openai_responses, user_path, async_): mock_openai_responses( text="Bob, Alice, Eve", response_id="resp_first", message_id="msg_first", ) mock_openai_responses( text="Terry", response_id="resp_second", message_id="msg_second", ) log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") # First prompt runner = CliRunner() args = ["three names \nfor a pet pelican", "--no-stream"] + ( ["--async"] if async_ else [] ) > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:171: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ________________________ test_llm_prompt_continue[True] ________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.AsyncStream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = mock_openai_responses = .add_response at 0x7f414b961d20> user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_prompt_continue_True_0/llm.datasette.io') async_ = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("async_", (False, True)) def test_llm_prompt_continue(httpx_mock, mock_openai_responses, user_path, async_): mock_openai_responses( text="Bob, Alice, Eve", response_id="resp_first", message_id="msg_first", ) mock_openai_responses( text="Terry", response_id="resp_second", message_id="msg_second", ) log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") # First prompt runner = CliRunner() args = ["three names \nfor a pet pelican", "--no-stream"] + ( ["--async"] if async_ else [] ) > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:171: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1116: in prompt response = asyncio.run(inner()) ^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:205: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:128: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/base_events.py:724: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1107: in inner text = await response.text() ^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2885: in execute completion = await client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:2964: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.AsyncStream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError _____________________ test_extract_fenced_code[args0-True] _____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_chat_returning_fenced_code = args = ['-x'], expect_just_code = True @pytest.mark.parametrize( "args,expect_just_code", ( (["-x"], True), (["--extract"], True), (["-x", "--async"], True), (["--extract", "--async"], True), # Use --no-stream here to ensure it passes test same as -x/--extract cases (["--no-stream"], False), ), ) def test_extract_fenced_code( mocked_openai_chat_returning_fenced_code, args, expect_just_code ): runner = CliRunner() > result = runner.invoke( cli, ["-m", "gpt-4o-mini", "--key", "x", "Write code"] + args, catch_exceptions=False, ) tests/test_llm.py:204: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________________ test_extract_fenced_code[args1-True] _____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_chat_returning_fenced_code = args = ['--extract'], expect_just_code = True @pytest.mark.parametrize( "args,expect_just_code", ( (["-x"], True), (["--extract"], True), (["-x", "--async"], True), (["--extract", "--async"], True), # Use --no-stream here to ensure it passes test same as -x/--extract cases (["--no-stream"], False), ), ) def test_extract_fenced_code( mocked_openai_chat_returning_fenced_code, args, expect_just_code ): runner = CliRunner() > result = runner.invoke( cli, ["-m", "gpt-4o-mini", "--key", "x", "Write code"] + args, catch_exceptions=False, ) tests/test_llm.py:204: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________________ test_extract_fenced_code[args2-True] _____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_chat_returning_fenced_code = args = ['-x', '--async'], expect_just_code = True @pytest.mark.parametrize( "args,expect_just_code", ( (["-x"], True), (["--extract"], True), (["-x", "--async"], True), (["--extract", "--async"], True), # Use --no-stream here to ensure it passes test same as -x/--extract cases (["--no-stream"], False), ), ) def test_extract_fenced_code( mocked_openai_chat_returning_fenced_code, args, expect_just_code ): runner = CliRunner() > result = runner.invoke( cli, ["-m", "gpt-4o-mini", "--key", "x", "Write code"] + args, catch_exceptions=False, ) tests/test_llm.py:204: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1116: in prompt response = asyncio.run(inner()) ^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:205: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:128: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/base_events.py:724: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1107: in inner text = await response.text() ^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1575: in execute completion = await client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:2952: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError _____________________ test_extract_fenced_code[args3-True] _____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_chat_returning_fenced_code = args = ['--extract', '--async'], expect_just_code = True @pytest.mark.parametrize( "args,expect_just_code", ( (["-x"], True), (["--extract"], True), (["-x", "--async"], True), (["--extract", "--async"], True), # Use --no-stream here to ensure it passes test same as -x/--extract cases (["--no-stream"], False), ), ) def test_extract_fenced_code( mocked_openai_chat_returning_fenced_code, args, expect_just_code ): runner = CliRunner() > result = runner.invoke( cli, ["-m", "gpt-4o-mini", "--key", "x", "Write code"] + args, catch_exceptions=False, ) tests/test_llm.py:204: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1116: in prompt response = asyncio.run(inner()) ^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:205: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/runners.py:128: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/asyncio/base_events.py:724: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1107: in inner text = await response.text() ^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1575: in execute completion = await client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:2952: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError ____________________ test_extract_fenced_code[args4-False] _____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_chat_returning_fenced_code = args = ['--no-stream'], expect_just_code = False @pytest.mark.parametrize( "args,expect_just_code", ( (["-x"], True), (["--extract"], True), (["-x", "--async"], True), (["--extract", "--async"], True), # Use --no-stream here to ensure it passes test same as -x/--extract cases (["--no-stream"], False), ), ) def test_extract_fenced_code( mocked_openai_chat_returning_fenced_code, args, expect_just_code ): runner = CliRunner() > result = runner.invoke( cli, ["-m", "gpt-4o-mini", "--key", "x", "Write code"] + args, catch_exceptions=False, ) tests/test_llm.py:204: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ________________________ test_extract_fenced_code_crlf _________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_extract_fenced_code_crlf(httpx_mock): """The CLI extracts fenced code when the model response uses CRLF.""" httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "model": "gpt-4o-mini", "usage": {}, "choices": [ { "message": { "content": 'Code:\r\n\r\n```python\r\nprint("ok")\r\n```\r\nDone.' } } ], }, headers={"Content-Type": "application/json"}, ) runner = CliRunner() > result = runner.invoke( cli, ["-m", "gpt-4o-mini", "--key", "x", "Write code", "--extract"], catch_exceptions=False, ) tests/test_llm.py:235: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ___________________________ test_openai_chat_stream ____________________________ mocked_openai_chat_stream = None user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_openai_chat_stream0/llm.datasette.io') def test_openai_chat_stream(mocked_openai_chat_stream, user_path): runner = CliRunner() result = runner.invoke(cli, ["-m", "gpt-3.5-turbo", "--key", "x", "Say hi"]) > assert result.exit_code == 0 E AssertionError: assert 1 == 0 E + where 1 = .exit_code tests/test_llm.py:249: AssertionError ____________________________ test_openai_completion ____________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NO...model': 'gpt-3.5-turbo-instruct', 'stream': False, 'prompt': 'Say this is a test', 'max_tokens': 256}, extra_json=None) stream = False, stream_cls = openai.Stream[openai.types.completion.Completion] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_completion = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_openai_completion0/llm.datasette.io') def test_openai_completion(mocked_openai_completion, user_path): log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") runner = CliRunner() > result = runner.invoke( cli, [ "-m", "gpt-3.5-turbo-instruct", "Say this is a test", "--no-stream", "--key", "x", ], catch_exceptions=False, ) tests/test_llm.py:260: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2976: in execute completion = client.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/completions.py:555: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NO...model': 'gpt-3.5-turbo-instruct', 'stream': False, 'prompt': 'Say this is a test', 'max_tokens': 256}, extra_json=None) stream = False, stream_cls = openai.Stream[openai.types.completion.Completion] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _______________ test_openai_completion_continue_includes_history _______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NO...model': 'gpt-3.5-turbo-instruct', 'stream': False, 'prompt': 'Say this is a test', 'max_tokens': 256}, extra_json=None) stream = False, stream_cls = openai.Stream[openai.types.completion.Completion] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_completion = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_openai_completion_continu0/llm.datasette.io') def test_openai_completion_continue_includes_history( mocked_openai_completion, user_path ): # A continued conversation reloaded from storage must send the # prior exchanges, not just the newest prompt - prompt.messages # carries them; conversation.responses does not. runner = CliRunner() base = ["-m", "gpt-3.5-turbo-instruct", "--no-stream", "--key", "x"] > result = runner.invoke(cli, base + ["Say this is a test"], catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:311: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2976: in execute completion = client.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/completions.py:555: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NO...model': 'gpt-3.5-turbo-instruct', 'stream': False, 'prompt': 'Say this is a test', 'max_tokens': 256}, extra_json=None) stream = False, stream_cls = openai.Stream[openai.types.completion.Completion] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________________ test_openai_completion_logprobs_stream ____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NO...rue, 'prompt': 'Say hi', 'logprobs': 2, 'max_tokens': 256, 'stream_options': {'include_usage': True}}, extra_json=None) stream = True, stream_cls = openai.Stream[openai.types.completion.Completion] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_completion_logprobs_stream = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_openai_completion_logprob0/llm.datasette.io') def test_openai_completion_logprobs_stream( mocked_openai_completion_logprobs_stream, user_path ): log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") runner = CliRunner() args = [ "-m", "gpt-3.5-turbo-instruct", "Say hi", "-o", "logprobs", "2", "--key", "x", ] > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:361: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1128: in prompt display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2957: in execute completion = client.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/completions.py:555: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NO...rue, 'prompt': 'Say hi', 'logprobs': 2, 'max_tokens': 256, 'stream_options': {'include_usage': True}}, extra_json=None) stream = True, stream_cls = openai.Stream[openai.types.completion.Completion] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ___________________ test_openai_completion_logprobs_nostream ___________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NO...el': 'gpt-3.5-turbo-instruct', 'stream': False, 'prompt': 'Say hi', 'logprobs': 2, 'max_tokens': 256}, extra_json=None) stream = False, stream_cls = openai.Stream[openai.types.completion.Completion] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_completion_logprobs = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_openai_completion_logprob1/llm.datasette.io') def test_openai_completion_logprobs_nostream( mocked_openai_completion_logprobs, user_path ): log_path = user_path / "logs.db" log_db = sqlite_utils.Database(str(log_path)) if "turns" in log_db.table_names(): with log_db.conn: log_db.execute("delete from turns") runner = CliRunner() args = [ "-m", "gpt-3.5-turbo-instruct", "Say hi", "-o", "logprobs", "2", "--key", "x", "--no-stream", ] > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:391: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2976: in execute completion = client.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/completions.py:555: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NO...el': 'gpt-3.5-turbo-instruct', 'stream': False, 'prompt': 'Say hi', 'logprobs': 2, 'max_tokens': 256}, extra_json=None) stream = False, stream_cls = openai.Stream[openai.types.completion.Completion] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ______________________ test_openai_localai_configuration _______________________ mocked_localai = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_openai_localai_configurat0/llm.datasette.io') def test_openai_localai_configuration(mocked_localai, user_path): log_path = user_path / "logs.db" sqlite_utils.Database(str(log_path)) # Write the configuration file config_path = user_path / "extra-openai-models.yaml" config_path.write_text(EXTRA_MODELS_YAML, "utf-8") # Run the prompt runner = CliRunner() prompt = "three names \nfor a pet pelican" result = runner.invoke(cli, ["--no-stream", "--model", "orca", prompt]) > assert result.exit_code == 0 E AssertionError: assert 1 == 0 E + where 1 = .exit_code tests/test_llm.py:423: AssertionError ________________ test_llm_prompt_continue_with_database[False] _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_prompt_continue_with_0') monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414be5ecf0> httpx_mock = mock_openai_responses = .add_response at 0x7f414baca980> user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_prompt_continue_with_0/user') custom_database_path = False @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("custom_database_path", (False, True)) def test_llm_prompt_continue_with_database( tmpdir, monkeypatch, httpx_mock, mock_openai_responses, user_path, custom_database_path, ): mock_openai_responses( text="Bob, Alice, Eve", response_id="resp_first", message_id="msg_first", ) mock_openai_responses( text="Terry", response_id="resp_second", message_id="msg_second", ) user_path = tmpdir / "user" custom_db_path = tmpdir / "custom_log.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) # First prompt runner = CliRunner() args = ["three names \nfor a pet pelican", "--no-stream"] if custom_database_path: args.extend(["--database", str(custom_db_path)]) > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:936: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________________ test_llm_prompt_continue_with_database[True] _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_prompt_continue_with_1') monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414baecf30> httpx_mock = mock_openai_responses = .add_response at 0x7f414b9824b0> user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_llm_prompt_continue_with_1/user') custom_database_path = True @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) @pytest.mark.parametrize("custom_database_path", (False, True)) def test_llm_prompt_continue_with_database( tmpdir, monkeypatch, httpx_mock, mock_openai_responses, user_path, custom_database_path, ): mock_openai_responses( text="Bob, Alice, Eve", response_id="resp_first", message_id="msg_first", ) mock_openai_responses( text="Terry", response_id="resp_second", message_id="msg_second", ) user_path = tmpdir / "user" custom_db_path = tmpdir / "custom_log.db" monkeypatch.setenv("LLM_USER_PATH", str(user_path)) # First prompt runner = CliRunner() args = ["three names \nfor a pet pelican", "--no-stream"] if custom_database_path: args.extend(["--database", str(custom_db_path)]) > result = runner.invoke(cli, args, catch_exceptions=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_llm.py:936: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...r', 'content': 'three names \nfor a pet pelican'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _______ test_endpoint_chat_completions_does_not_log_or_leak_default_key ________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...sages': [{'role': 'user', 'content': 'Hello'}], 'reasoning_effort': }, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_chat_completions0/llm.datasette.io') monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c82a040> def test_endpoint_chat_completions_does_not_log_or_leak_default_key( httpx_mock, user_path, monkeypatch ): base_url = "https://example.test/v1" _add_chat_response(httpx_mock, base_url, "Hello from the endpoint") monkeypatch.setenv("OPENAI_API_KEY", "real-default-openai-key") > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Hello", "-m", "test-model", "--no-stream", "-H", "X-Test", "one", "-o", "reasoning_effort", "low", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:170: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...sages': [{'role': 'user', 'content': 'Hello'}], 'reasoning_effort': }, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __________________ test_endpoint_chat_completions_attachment ___________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... 'image_url', 'image_url': {'url': 'data:image/png;base64,iVBORw0KGgplbmRwb2ludCBhdHRhY2htZW50'}}]}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_chat_completions1/llm.datasette.io') tmp_path = PosixPath('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_chat_completions1') def test_endpoint_chat_completions_attachment(httpx_mock, user_path, tmp_path): base_url = "https://attachments.example.test/v1" _add_chat_response(httpx_mock, base_url, "A test image") image_bytes = b"\x89PNG\r\n\x1a\nendpoint attachment" image_path = tmp_path / "image.png" image_path.write_bytes(image_bytes) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Describe this", "-m", "test-model", "--no-stream", "-a", str(image_path), ], catch_exceptions=False, ) tests/test_openai_endpoint.py:212: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... 'image_url', 'image_url': {'url': 'data:image/png;base64,iVBORw0KGgplbmRwb2ludCBhdHRhY2htZW50'}}]}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________________________ test_endpoint_template ____________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... 'json_schema', 'json_schema': {'name': 'output', 'schema': {'type': 'object'}}}, 'temperature': 0.4}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_template0/llm.datasette.io') templates_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_template0/llm.datasette.io/templates') def test_endpoint_template(httpx_mock, user_path, templates_path): base_url = "https://templates.example.test/v1" _add_chat_response(httpx_mock, base_url, "Template response") (templates_path / "endpoint.yaml").write_text( """ model: template-model system: You are $persona prompt: "Question: $input" options: temperature: 0.4 schema_object: type: object properties: answer: type: string required: - answer attachment_types: - type: image/jpeg value: https://images.example.test/template.jpg """.strip(), "utf-8", ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Where?", "--template", "endpoint", "--schema", '{"type": "object"}', "--param", "persona", "concise", "--no-stream", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:273: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... 'json_schema', 'json_schema': {'name': 'output', 'schema': {'type': 'object'}}}, 'temperature': 0.4}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________ test_endpoint_template_schema_object_used_when_no_cli_schema _________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...'schema': {'type': 'object', 'properties': {'answer': {'type': 'string'}}, 'required': ['answer']}}}}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_template_schema_0/llm.datasette.io') templates_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_template_schema_0/llm.datasette.io/templates') def test_endpoint_template_schema_object_used_when_no_cli_schema( httpx_mock, user_path, templates_path ): base_url = "https://templates2.example.test/v1" _add_chat_response(httpx_mock, base_url, "Template response 2") (templates_path / "schemaonly.yaml").write_text( """ model: schema-model schema_object: type: object properties: answer: type: string required: - answer """.strip(), "utf-8", ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "test question", "--template", "schemaonly", "--no-stream", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:344: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...'schema': {'type': 'object', 'properties': {'answer': {'type': 'string'}}, 'required': ['answer']}}}}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________________________ test_endpoint_schema _____________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...roperties': {'name': {'type': 'string'}, 'age': {'type': 'integer'}}, 'required': ['name', 'age']}}}}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_schema0/llm.datasette.io') def test_endpoint_schema(httpx_mock, user_path): base_url = "https://schema.example.test/v1" _add_chat_response(httpx_mock, base_url, '{"name": "Cleo", "age": 10}') > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Invent a dog", "-m", "test-model", "--schema", "name, age int", "--no-stream", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:377: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...roperties': {'name': {'type': 'string'}, 'age': {'type': 'integer'}}, 'required': ['name', 'age']}}}}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________ test_endpoint_schema_by_id_from_existing_logs_database ____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...t', 'schema': {'type': 'object', 'properties': {'name': {'type': 'string'}}, 'required': ['name']}}}}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_schema_by_id_fro0/llm.datasette.io') def test_endpoint_schema_by_id_from_existing_logs_database(httpx_mock, user_path): base_url = "https://schema-id.example.test/v1" _add_chat_response(httpx_mock, base_url, '{"name": "Cleo"}') schema = { "type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"], } db = sqlite_utils.Database(str(user_path / "logs.db")) migrate(db) db["schemas"].insert({"id": "dog-schema", "content": json.dumps(schema)}) assert (user_path / "logs.db").exists() > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Invent a dog", "-m", "test-model", "--schema", "dog-schema", "--no-stream", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:425: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...t', 'schema': {'type': 'object', 'properties': {'name': {'type': 'string'}}, 'required': ['name']}}}}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_endpoint_static_template_runs_once_on_terminal ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... 'test-model', 'stream': False, 'messages': [{'role': 'user', 'content': 'List five pelican names'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_static_template_0/llm.datasette.io') templates_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_static_template_0/llm.datasette.io/templates') monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414d498e50> def test_endpoint_static_template_runs_once_on_terminal( httpx_mock, user_path, templates_path, monkeypatch ): base_url = "https://terminal-template.example.test/v1" _add_chat_response(httpx_mock, base_url, "Five pelicans") (templates_path / "pelican.yaml").write_text( "prompt: List five pelican names\n", "utf-8" ) monkeypatch.setattr("click.testing._NamedTextIOWrapper.isatty", lambda self: True) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "-m", "test-model", "-t", "pelican", "--no-stream", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:479: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... 'test-model', 'stream': False, 'messages': [{'role': 'user', 'content': 'List five pelican names'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ______________________ test_endpoint_tools_and_functions _______________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ption': 'Return the installed version of llm', 'parameters': {'properties': {}, 'type': 'object'}}}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_tools_and_functi0/llm.datasette.io') def test_endpoint_tools_and_functions(httpx_mock, user_path): base_url = "https://tools.example.test/v1" _add_chat_tool_call_response(httpx_mock, base_url, "multiply", {"a": 6, "b": 7}) _add_chat_response(httpx_mock, base_url, "The answer is 42") > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "What is 6 * 7?", "-m", "test-model", "--no-stream", "-T", "llm_version", "--functions", ( "def multiply(a: int, b: int) -> int:\n" ' "Multiply two numbers."\n' " return a * b\n" ), ], catch_exceptions=False, ) tests/test_openai_endpoint.py:507: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:3018: in stream_events for event in response_item.stream_events(): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ption': 'Return the installed version of llm', 'parameters': {'properties': {}, 'type': 'object'}}}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _______________________ test_endpoint_streams_by_default _______________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... True, 'messages': [{'role': 'user', 'content': 'Hello'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_streams_by_defau0/llm.datasette.io') def test_endpoint_streams_by_default(httpx_mock, user_path): base_url = "https://stream.example.test/v1" httpx_mock.add_response( method="POST", url=f"{base_url}/chat/completions", stream=IteratorStream(_chat_stream_events()), headers={"Content-Type": "text/event-stream"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Hello", "-m", "test-model", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:572: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... True, 'messages': [{'role': 'user', 'content': 'Hello'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _______________________ test_endpoint_uses_explicit_key ________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...son_data={'model': 'test-model', 'stream': False, 'messages': [{'role': 'user', 'content': 'Hello'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_uses_explicit_ke0/llm.datasette.io') def test_endpoint_uses_explicit_key(httpx_mock, user_path): base_url = "https://example.test/v1" _add_chat_response(httpx_mock, base_url, "Authenticated") > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Hello", "-m", "test-model", "--no-stream", "--key", "endpoint-key", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:597: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...son_data={'model': 'test-model', 'stream': False, 'messages': [{'role': 'user', 'content': 'Hello'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_endpoint_lists_models_without_model_or_logging ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='get', url='/models', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_GIVE...ts=None, security={'bearer_auth': True}, synthesize_event_and_data=None, content=None, json_data=None, extra_json=None) stream = False, stream_cls = None def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_lists_models_wit0/llm.datasette.io') monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f414c829550> def test_endpoint_lists_models_without_model_or_logging( httpx_mock, user_path, monkeypatch ): base_url = "https://models.example.test/v1" monkeypatch.setenv("OPENAI_API_KEY", "real-default-openai-key") httpx_mock.add_response( method="GET", url=f"{base_url}/models", json={ "object": "list", "data": [ { "id": "first-model", "object": "model", "created": 1, "owned_by": "example", }, { "id": "second-model", "object": "model", "created": 2, "owned_by": "example", }, ], }, headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "--models", "-H", "X-Test", "one", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:648: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:740: in endpoint available_models = model.get_client(key).models.list() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/models.py:95: in list return self._get_api_list( /usr/lib/python3.15/site-packages/openai/_base_client.py:1526: in get_api_list return self._request_api_list(model, page, opts) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1325: in _request_api_list return self.request(page, options, stream=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='get', url='/models', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_GIVE...ts=None, security={'bearer_auth': True}, synthesize_event_and_data=None, content=None, json_data=None, extra_json=None) stream = False, stream_cls = None def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________ test_endpoint_models_surfaces_error_from_successful_response _________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='get', url='/models', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_GIVE...ts=None, security={'bearer_auth': True}, synthesize_event_and_data=None, content=None, json_data=None, extra_json=None) stream = False, stream_cls = None def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_models_surfaces_0/llm.datasette.io') def test_endpoint_models_surfaces_error_from_successful_response(httpx_mock, user_path): base_url = "https://models-error.example.test" httpx_mock.add_response( method="GET", url=f"{base_url}/models", json={"error": "Unexpected endpoint or method. (GET /models)"}, headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, ["openai", "endpoint", base_url, "--models"], catch_exceptions=False, ) tests/test_openai_endpoint.py:679: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:740: in endpoint available_models = model.get_client(key).models.list() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/models.py:95: in list return self._get_api_list( /usr/lib/python3.15/site-packages/openai/_base_client.py:1526: in get_api_list return self._request_api_list(model, page, opts) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1325: in _request_api_list return self.request(page, options, stream=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='get', url='/models', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_GIVE...ts=None, security={'bearer_auth': True}, synthesize_event_and_data=None, content=None, json_data=None, extra_json=None) stream = False, stream_cls = None def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________________________ test_endpoint_responses_api __________________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...}, 'store': False, 'text': {'verbosity': }}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_responses_api0/llm.datasette.io') def test_endpoint_responses_api(httpx_mock, user_path): base_url = "https://responses.example.test/v1" httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=_responses_payload("Hello from Responses"), headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Hello", "-m", "test-model", "--responses", "--no-stream", "-o", "verbosity", "low", "-o", "reasoning_effort", "low", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:699: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...}, 'store': False, 'text': {'verbosity': }}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________ test_endpoint_responses_reasoning_summary_option[auto] ____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_... 'content': 'Hello'}], 'reasoning': {'summary': }, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_responses_reason0/llm.datasette.io') reasoning_summary = 'auto' @pytest.mark.parametrize("reasoning_summary", ("auto", "concise", "detailed")) def test_endpoint_responses_reasoning_summary_option( httpx_mock, user_path, reasoning_summary ): base_url = "https://responses-summary.example.test/v1" httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=_responses_payload("Hello from Responses"), headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Hello", "-m", "test-model", "--responses", "--no-stream", "-o", "reasoning_summary", reasoning_summary, ], catch_exceptions=False, ) tests/test_openai_endpoint.py:746: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_... 'content': 'Hello'}], 'reasoning': {'summary': }, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __________ test_endpoint_responses_reasoning_summary_option[concise] ___________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ent': 'Hello'}], 'reasoning': {'summary': }, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_responses_reason1/llm.datasette.io') reasoning_summary = 'concise' @pytest.mark.parametrize("reasoning_summary", ("auto", "concise", "detailed")) def test_endpoint_responses_reasoning_summary_option( httpx_mock, user_path, reasoning_summary ): base_url = "https://responses-summary.example.test/v1" httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=_responses_payload("Hello from Responses"), headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Hello", "-m", "test-model", "--responses", "--no-stream", "-o", "reasoning_summary", reasoning_summary, ], catch_exceptions=False, ) tests/test_openai_endpoint.py:746: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ent': 'Hello'}], 'reasoning': {'summary': }, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __________ test_endpoint_responses_reasoning_summary_option[detailed] __________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...t': 'Hello'}], 'reasoning': {'summary': }, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_responses_reason2/llm.datasette.io') reasoning_summary = 'detailed' @pytest.mark.parametrize("reasoning_summary", ("auto", "concise", "detailed")) def test_endpoint_responses_reasoning_summary_option( httpx_mock, user_path, reasoning_summary ): base_url = "https://responses-summary.example.test/v1" httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=_responses_payload("Hello from Responses"), headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Hello", "-m", "test-model", "--responses", "--no-stream", "-o", "reasoning_summary", reasoning_summary, ], catch_exceptions=False, ) tests/test_openai_endpoint.py:746: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...t': 'Hello'}], 'reasoning': {'summary': }, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________________ test_endpoint_responses_api_attachment ____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...mage', 'image_url': 'https://images.example.test/test.jpg', 'detail': 'original'}]}], 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_responses_api_at0/llm.datasette.io') def test_endpoint_responses_api_attachment(httpx_mock, user_path): base_url = "https://responses-attachments.example.test/v1" httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=_responses_payload("A remote image"), headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Describe this", "-m", "test-model", "--responses", "--no-stream", "--at", "https://images.example.test/test.jpg", "image/jpeg", "-o", "image_detail", "original", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:816: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...mage', 'image_url': 'https://images.example.test/test.jpg', 'detail': 'original'}]}], 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ___________________ test_endpoint_responses_api_schema_multi ___________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ge': {'type': 'integer'}}, 'required': ['name', 'age']}}}, 'required': ['items']}, 'strict': False}}}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_responses_api_sc0/llm.datasette.io') def test_endpoint_responses_api_schema_multi(httpx_mock, user_path): base_url = "https://responses-schema.example.test/v1" httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=_responses_payload('{"items": [{"name": "Cleo", "age": 10}]}'), headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Invent a dog", "-m", "test-model", "--responses", "--schema-multi", "name, age int", "--no-stream", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:867: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ge': {'type': 'integer'}}, 'required': ['name', 'age']}}}, 'required': ['items']}, 'strict': False}}}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ______________________ test_endpoint_responses_api_tools _______________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...': {'a': {'type': 'integer'}, 'b': {'type': 'integer'}}, 'required': ['a', 'b'], 'type': 'object'}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_responses_api_to0/llm.datasette.io') def test_endpoint_responses_api_tools(httpx_mock, user_path): base_url = "https://responses-tools.example.test/v1" httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=_responses_tool_call_payload("multiply", {"a": 6, "b": 7}), headers={"Content-Type": "application/json"}, ) httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=_responses_payload("The answer is 42"), headers={"Content-Type": "application/json"}, ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "What is 6 * 7?", "-m", "test-model", "--responses", "--no-stream", "--functions", ( "def multiply(a: int, b: int) -> int:\n" ' "Multiply two numbers."\n' " return a * b\n" ), ], catch_exceptions=False, ) tests/test_openai_endpoint.py:926: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:3018: in stream_events for event in response_item.stream_events(): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...': {'a': {'type': 'integer'}, 'b': {'type': 'integer'}}, 'required': ['a', 'b'], 'type': 'object'}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _______________ test_endpoint_responses_api_raw_server_side_tool _______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...{'type': 'openrouter:web_search', 'parameters': {'engine': 'exa', 'max_results': 2, 'max_uses': 1}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_responses_api_ra0/llm.datasette.io') def test_endpoint_responses_api_raw_server_side_tool(httpx_mock, user_path): base_url = "https://raw-tools.example.test/v1" response_payload = _responses_payload("Search complete") response_payload["output"].insert( 0, { "id": "st_test", "type": "openrouter:web_search", "status": "completed", "action": { "type": "search", "query": "latest news", "sources": [{"type": "url", "url": "https://example.test/news"}], }, }, ) httpx_mock.add_response( method="POST", url=f"{base_url}/responses", json=response_payload, headers={"Content-Type": "application/json"}, ) tool_spec = { "type": "openrouter:web_search", "parameters": {"engine": "exa", "max_results": 2, "max_uses": 1}, } > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "Search for the latest news", "-m", "test-model", "--responses", "--no-stream", "-T", f"ServerSideTool(spec={json.dumps(tool_spec)})", ], catch_exceptions=False, ) tests/test_openai_endpoint.py:996: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:3018: in stream_events for event in response_item.stream_events(): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...{'type': 'openrouter:web_search', 'parameters': {'engine': 'exa', 'max_results': 2, 'max_uses': 1}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ________________ test_endpoint_reads_one_off_prompt_from_stdin _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...model': 'test-model', 'stream': False, 'messages': [{'role': 'user', 'content': 'Hello from stdin'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_reads_one_off_pr0/llm.datasette.io') def test_endpoint_reads_one_off_prompt_from_stdin(httpx_mock, user_path): base_url = "https://stdin.example.test/v1" _add_chat_response(httpx_mock, base_url, "From stdin") > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "-m", "test-model", "--no-stream", ], input="Hello from stdin", catch_exceptions=False, ) tests/test_openai_endpoint.py:1024: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...model': 'test-model', 'stream': False, 'messages': [{'role': 'user', 'content': 'Hello from stdin'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________________ test_endpoint_without_prompt_waits_for_stdin _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...-model', 'stream': False, 'messages': [{'role': 'user', 'content': 'Hello after waiting for stdin'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_without_prompt_w0/llm.datasette.io') monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f4149b5d6a0> def test_endpoint_without_prompt_waits_for_stdin(httpx_mock, user_path, monkeypatch): base_url = "https://terminal-stdin.example.test/v1" _add_chat_response(httpx_mock, base_url, "From awaited stdin") monkeypatch.setattr("click.testing._NamedTextIOWrapper.isatty", lambda self: True) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "-m", "test-model", "--no-stream", ], input="Hello after waiting for stdin", catch_exceptions=False, ) tests/test_openai_endpoint.py:1049: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:821: in endpoint display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...-model', 'stream': False, 'messages': [{'role': 'user', 'content': 'Hello after waiting for stdin'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _______________ test_endpoint_interactive_chat_preserves_history _______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...rameters': {'properties': {'value': {'type': 'string'}}, 'required': ['value'], 'type': 'object'}}}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = user_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_interactive_chat0/llm.datasette.io') templates_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_endpoint_interactive_chat0/llm.datasette.io/templates') def test_endpoint_interactive_chat_preserves_history( httpx_mock, user_path, templates_path ): base_url = "https://chat.example.test/v1" _add_chat_response(httpx_mock, base_url, "First answer") _add_chat_response(httpx_mock, base_url, "Second answer") (templates_path / "endpoint-chat.yaml").write_text( 'prompt: "Question: $input"\n', "utf-8" ) > result = CliRunner().invoke( cli, [ "openai", "endpoint", base_url, "-m", "test-model", "--chat", "--no-stream", "--system", "Be brief", "--template", "endpoint-chat", "--functions", ( "def lookup(value: str) -> str:\n" ' "Look up a value."\n' " return value\n" ), "--at", "https://images.example.test/context.jpg", "image/jpeg", ], input="First question\nSecond question\nquit\n", catch_exceptions=False, ) tests/test_openai_endpoint.py:1082: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:776: in endpoint _run_chat( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:213: in _run_chat display_stream_events( ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:111: in display_stream_events for event in events: ^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:3018: in stream_events for event in response_item.stream_events(): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...rameters': {'properties': {'value': {'type': 'string'}}, 'required': ['value'], 'type': 'object'}}}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _ TestBuildMessagesConversationHistory.test_no_double_emission_from_conversation_prompt_flow _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Q1'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = chat_model = httpx_mock = def test_no_double_emission_from_conversation_prompt_flow( self, chat_model, httpx_mock ): # Two staged responses so conv.prompt twice can complete. httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "model": "gpt-4o-mini", "usage": { "prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2, }, "choices": [ { "message": {"role": "assistant", "content": "A1"}, "finish_reason": "stop", } ], }, headers={"Content-Type": "application/json"}, ) httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "model": "gpt-4o-mini", "usage": { "prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2, }, "choices": [ { "message": {"role": "assistant", "content": "A2"}, "finish_reason": "stop", } ], }, headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-4o-mini") conv = model.conversation() r1 = conv.prompt("Q1", key=API_KEY, stream=False) > r1.text() tests/test_openai_messages.py:374: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Q1'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __ TestStreamingExecuteYieldsStreamEvents.test_text_stream_yields_text_events __ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_text_stream_yields_text_events(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_text_stream()), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_model("gpt-4o-mini") response = model.prompt("hi", key=API_KEY) > events = list(response.stream_events()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_messages.py:399: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _ TestStreamingExecuteYieldsStreamEvents.test_text_stream_plain_iteration_still_returns_strings _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_text_stream_plain_iteration_still_returns_strings(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_text_stream()), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_model("gpt-4o-mini") response = model.prompt("hi", key=API_KEY) > chunks = list(response) ^^^^^^^^^^^^^^ tests/test_openai_messages.py:417: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __ TestStreamingExecuteYieldsStreamEvents.test_text_stream_messages_assembled __ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_text_stream_messages_assembled(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_text_stream()), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_model("gpt-4o-mini") response = model.prompt("hi", key=API_KEY) > response.text() tests/test_openai_messages.py:430: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _ TestStreamingExecuteYieldsStreamEvents.test_tool_call_stream_yields_name_and_args_events _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...parameters': {'properties': {'city': {'type': 'string'}}, 'required': ['city'], 'type': 'object'}}}]}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_tool_call_stream_yields_name_and_args_events(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_tool_call_stream()), headers={"Content-Type": "text/event-stream"}, ) def get_weather(city: str) -> str: "Look up the weather." return "sunny" model = llm.get_model("gpt-4o-mini") response = model.prompt("weather?", tools=[get_weather], key=API_KEY) > events = list(response.stream_events()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_messages.py:449: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...parameters': {'properties': {'city': {'type': 'string'}}, 'required': ['city'], 'type': 'object'}}}]}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _ TestStreamingExecuteYieldsStreamEvents.test_tool_call_registered_via_add_tool_call _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...parameters': {'properties': {'city': {'type': 'string'}}, 'required': ['city'], 'type': 'object'}}}]}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_tool_call_registered_via_add_tool_call(self, httpx_mock): """response.tool_calls() still works — chain/execute relies on it.""" httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_tool_call_stream()), headers={"Content-Type": "text/event-stream"}, ) def get_weather(city: str) -> str: "Look up the weather." return "sunny" model = llm.get_model("gpt-4o-mini") response = model.prompt("weather?", tools=[get_weather], key=API_KEY) > response.text() tests/test_openai_messages.py:478: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...parameters': {'properties': {'city': {'type': 'string'}}, 'required': ['city'], 'type': 'object'}}}]}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _ TestStreamingExecuteYieldsStreamEvents.test_text_then_tool_call_part_index_advances _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo....', 'parameters': {'properties': {'c': {'type': 'integer'}}, 'required': ['c'], 'type': 'object'}}}]}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_text_then_tool_call_part_index_advances(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_text_then_tool_call_stream()), headers={"Content-Type": "text/event-stream"}, ) def get_weather(c: int) -> str: "Weather." return "sunny" model = llm.get_model("gpt-4o-mini") response = model.prompt("q", tools=[get_weather], key=API_KEY) > response.text() tests/test_openai_messages.py:499: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo....', 'parameters': {'properties': {'c': {'type': 'integer'}}, 'required': ['c'], 'type': 'object'}}}]}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _ TestAsyncStreamingExecuteYieldsStreamEvents.test_text_stream_yields_text_events _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = @pytest.mark.asyncio async def test_text_stream_yields_text_events(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_text_stream()), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_async_model("gpt-4o-mini") response = model.prompt("hi", key=API_KEY) events = [] > async for event in response.astream_events(): tests/test_openai_messages.py:523: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2556: in astream_events chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1524: in execute completion = await client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:2952: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.AsyncStream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError _ TestReasoningTokenCount.test_redacted_reasoning_part_emitted_when_count_present _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_redacted_reasoning_part_emitted_when_count_present(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_text_stream_with_reasoning_usage(150)), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_model("gpt-4o-mini") response = model.prompt("hi", key=API_KEY) > response.text() tests/test_openai_messages.py:560: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ______ TestReasoningTokenCount.test_no_reasoning_part_when_zero_or_absent ______ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_no_reasoning_part_when_zero_or_absent(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", stream=IteratorStream(_text_stream_with_reasoning_usage(0)), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_model("gpt-4o-mini") response = model.prompt("hi", key=API_KEY) > response.text() tests/test_openai_messages.py:580: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1406: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...m': True, 'messages': [{'role': 'user', 'content': 'hi'}], 'stream_options': {'include_usage': True}}, extra_json=None) stream = True stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _ TestNonStreamingExecuteYieldsStreamEvents.test_non_streaming_text_yields_single_event _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'hi'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: self = httpx_mock = def test_non_streaming_text_yields_single_event(self, httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "model": "gpt-4o-mini", "usage": { "prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2, }, "choices": [ { "message": {"role": "assistant", "content": "Hello"}, "finish_reason": "stop", } ], }, headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-4o-mini") response = model.prompt("hi", key=API_KEY, stream=False) > events = list(response.stream_events()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_messages.py:610: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo... json_data={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'hi'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_responses_web_search_request_and_result_capture _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...}, 'store': False, 'tools': [{'type': 'web_search', 'filters': {'allowed_domains': ['openai.com']}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_responses_web_search_request_and_result_capture(httpx_mock): sources = [ {"type": "url", "url": "https://openai.com/news/"}, {"type": "url", "url": "https://example.com/report"}, ] results = [ { "type": "image_result", "image_url": "https://example.com/image.jpg", "source_website_url": "https://example.com/report", "thumbnail_url": "https://example.com/thumb.jpg", "caption": "An example image", } ] response_json = _text_response_json(text="A cited answer") response_json["output"].insert( 0, { "type": "web_search_call", "id": "ws_123", "status": "completed", "action": { "type": "search", "query": "OpenAI news", "queries": ["OpenAI news"], "sources": sources, }, "results": results, }, ) httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json=response_json, headers={"Content-Type": "application/json"}, ) response = llm.get_model("gpt-5.6-luna").prompt( "Search for OpenAI news", tools=[ WebSearch( allowed_domains=["openai.com"], include_sources=True, include_results=True, ) ], stream=False, key="test", ) > assert response.text() == "A cited answer" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:231: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...}, 'store': False, 'tools': [{'type': 'web_search', 'filters': {'allowed_domains': ['openai.com']}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ___________ test_responses_mixes_function_and_code_interpreter_tools ___________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ype': 'object'}}, {'type': 'code_interpreter', 'container': {'type': 'auto', 'memory_limit': '4g'}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_responses_mixes_function_and_code_interpreter_tools(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json=_text_response_json(), headers={"Content-Type": "application/json"}, ) def multiply(a: int, b: int) -> int: return a * b model = llm.get_model("gpt-5.6-luna") response = model.prompt( "Calculate 111 * 333 using the python tool", tools=[multiply, CodeInterpreter(memory_limit="4g")], stream=False, key="test", ) > assert response.text() == "ok" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:310: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ype': 'object'}}, {'type': 'code_interpreter', 'container': {'type': 'auto', 'memory_limit': '4g'}}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ________ test_responses_raw_server_tool_passthrough_on_custom_endpoint _________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...user', 'content': 'Search'}], 'store': False, 'tools': [{'type': 'browser_search', 'depth': 'deep'}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_responses_raw_server_tool_passthrough_on_custom_endpoint(httpx_mock): httpx_mock.add_response( method="POST", url="https://example.test/v1/responses", json=_text_response_json(model="custom-model"), headers={"Content-Type": "application/json"}, ) model = Responses( "custom-model", api_base="https://example.test/v1", supports_tools=False, ) raw_spec = {"type": "browser_search", "depth": "deep"} response = model.prompt( "Search", tools=[llm.ServerSideTool(raw_spec)], stream=False, key="test" ) > assert response.text() == "ok" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:342: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...user', 'content': 'Search'}], 'store': False, 'tools': [{'type': 'browser_search', 'depth': 'deep'}]}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ________________ test_async_responses_code_interpreter_request _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...alse, 'tools': [{'type': 'code_interpreter', 'container': {'type': 'auto', 'file_ids': ['file-1']}}]}, extra_json=None) stream = False stream_cls = openai.AsyncStream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = @pytest.mark.asyncio async def test_async_responses_code_interpreter_request(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json=_text_response_json(), headers={"Content-Type": "application/json"}, ) model = llm.get_async_model("gpt-5.6-luna") response = model.prompt( "Calculate", tools=[CodeInterpreter(file_ids=["file-1"])], stream=False, key="test", ) > assert await response.text() == "ok" ^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_responses.py:382: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2885: in execute completion = await client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:2964: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...alse, 'tools': [{'type': 'code_interpreter', 'container': {'type': 'auto', 'file_ids': ['file-1']}}]}, extra_json=None) stream = False stream_cls = openai.AsyncStream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError ___________________ test_async_responses_web_search_request ____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...{'summary': 'auto'}, 'store': False, 'tools': [{'type': 'web_search', 'external_web_access': False}]}, extra_json=None) stream = False stream_cls = openai.AsyncStream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = @pytest.mark.asyncio async def test_async_responses_web_search_request(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json=_text_response_json(), headers={"Content-Type": "application/json"}, ) response = llm.get_async_model("gpt-5.6-luna").prompt( "Search", tools=[WebSearch(external_web_access=False, include_sources=True)], stream=False, key="test", ) > assert await response.text() == "ok" ^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_responses.py:411: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2885: in execute completion = await client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:2964: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...{'summary': 'auto'}, 'store': False, 'tools': [{'type': 'web_search', 'external_web_access': False}]}, extra_json=None) stream = False stream_cls = openai.AsyncStream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError _______________ test_chat_completions_opt_out_dispatches_to_chat _______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo..., json_data={'model': 'gpt-5.5', 'stream': False, 'messages': [{'role': 'user', 'content': 'hello'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_chat_completions_opt_out_dispatches_to_chat(httpx_mock): """When chat_completions=1 is passed, the request must hit /v1/chat/completions, not /v1/responses.""" httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "id": "chatcmpl-x", "object": "chat.completion", "model": "gpt-5.5", "choices": [ { "index": 0, "message": {"role": "assistant", "content": "hi from chat"}, "finish_reason": "stop", } ], "usage": {"prompt_tokens": 1, "completion_tokens": 2, "total_tokens": 3}, }, headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-5.5") response = model.prompt( "hello", stream=False, chat_completions=True, reasoning_summary="detailed", key="test", ) > assert response.text() == "hi from chat" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:626: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2493: in execute yield from chat.execute(prompt, stream, response, conversation, key) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo..., json_data={'model': 'gpt-5.5', 'stream': False, 'messages': [{'role': 'user', 'content': 'hello'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __________________ test_default_routes_to_responses_endpoint ___________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'hello'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_default_routes_to_responses_endpoint(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_test_1", "object": "response", "created_at": 1, "model": "gpt-5.5", "output": [ { "type": "message", "id": "msg_1", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "hi from responses", "annotations": [], } ], } ], "usage": { "input_tokens": 5, "output_tokens": 3, "total_tokens": 8, }, "status": "completed", }, headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-5.5") response = model.prompt("hello", stream=False, key="test") > assert response.text() == "hi from responses" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:666: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'hello'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ______ test_hide_reasoning_omits_reasoning_summary_from_responses_request ______ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...e': ['reasoning.encrypted_content'], 'input': [{'role': 'user', 'content': 'hello'}], 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_hide_reasoning_omits_reasoning_summary_from_responses_request(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_test_1", "object": "response", "created_at": 1, "model": "gpt-5.5", "output": [ { "type": "message", "id": "msg_1", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "hidden", "annotations": [], } ], } ], "usage": { "input_tokens": 5, "output_tokens": 3, "total_tokens": 8, }, "status": "completed", }, headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-5.5") response = model.prompt("hello", stream=False, key="test", hide_reasoning=True) > assert response.text() == "hidden" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:710: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...e': ['reasoning.encrypted_content'], 'input': [{'role': 'user', 'content': 'hello'}], 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____ test_non_reasoning_responses_model_omits_encrypted_reasoning_include _____ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...'model': 'gpt-4.1', 'stream': False, 'input': [{'role': 'user', 'content': 'hello'}], 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_non_reasoning_responses_model_omits_encrypted_reasoning_include(httpx_mock): from llm.default_plugins.openai_models import Responses httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_test_1", "object": "response", "created_at": 1, "model": "gpt-4.1", "output": [ { "type": "message", "id": "msg_1", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "hi from gpt-4.1", "annotations": [], } ], } ], "usage": { "input_tokens": 5, "output_tokens": 3, "total_tokens": 8, }, "status": "completed", }, headers={"Content-Type": "application/json"}, ) model = Responses("gpt-4.1", vision=True, supports_schema=True, supports_tools=True) response = model.prompt("hello", stream=False, key="test") > assert response.text() == "hi from gpt-4.1" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:755: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...'model': 'gpt-4.1', 'stream': False, 'input': [{'role': 'user', 'content': 'hello'}], 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError __________ test_responses_reply_sends_prior_assistant_text_as_string ___________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ole': 'user', 'content': 'Say exactly: first-ok'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_responses_reply_sends_prior_assistant_text_as_string(httpx_mock): """response.reply() should send the same simple history shape a direct openai-python Responses call would use for a text-only assistant turn.""" def response_json(response_id, message_id, text): return { "id": response_id, "object": "response", "created_at": 1, "model": "gpt-5.5", "output": [ { "type": "message", "id": message_id, "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": text, "annotations": [], } ], } ], "usage": { "input_tokens": 5, "output_tokens": 3, "total_tokens": 8, }, "status": "completed", } httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json=response_json("resp_1", "msg_1", "first-ok"), headers={"Content-Type": "application/json"}, ) httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json=response_json("resp_2", "msg_2", "followup-ok"), headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-5.5") first = model.prompt("Say exactly: first-ok", stream=False, key="test") > second = first.reply("Say exactly: followup-ok", stream=False, key="test") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_responses.py:881: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1801: in reply self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ole': 'user', 'content': 'Say exactly: first-ok'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________________ test_service_tier_sent_to_responses_endpoint _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'hello'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_service_tier_sent_to_responses_endpoint(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_test_1", "object": "response", "created_at": 1, "model": "gpt-5.6-sol", "output": [ { "type": "message", "id": "msg_1", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "fast reply", "annotations": [], } ], } ], "usage": { "input_tokens": 5, "output_tokens": 3, "total_tokens": 8, }, "status": "completed", "service_tier": "priority", }, headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-5.6-sol") response = model.prompt("hello", stream=False, service_tier="fast", key="test") > assert response.text() == "fast reply" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:1073: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'hello'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _____________ test_service_tier_sent_to_chat_completions_fallback ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo....6-sol', 'stream': False, 'service_tier': 'fast', 'messages': [{'role': 'user', 'content': 'hello'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_service_tier_sent_to_chat_completions_fallback(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/chat/completions", json={ "id": "chatcmpl-x", "object": "chat.completion", "model": "gpt-5.6-sol", "choices": [ { "index": 0, "message": {"role": "assistant", "content": "fast chat"}, "finish_reason": "stop", } ], "usage": {"prompt_tokens": 1, "completion_tokens": 2, "total_tokens": 3}, }, headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-5.6-sol") response = model.prompt( "hello", stream=False, chat_completions=True, service_tier="fast", key="test" ) > assert response.text() == "fast chat" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:1103: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2493: in execute yield from chat.execute(prompt, stream, response, conversation, key) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo....6-sol', 'stream': False, 'service_tier': 'fast', 'messages': [{'role': 'user', 'content': 'hello'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ________________ test_responses_streams_reasoning_summary_text _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'hello'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = True stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_responses_streams_reasoning_summary_text(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", stream=IteratorStream(_responses_reasoning_summary_stream()), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_model("gpt-5.5") response = model.prompt("hello", key="test") > events = list(response.stream_events()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_responses.py:1118: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2511: in execute stream_obj = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'hello'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = True stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ________ test_responses_reasoning_metadata_refreshed_from_final_payload ________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'hello'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = True stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_responses_reasoning_metadata_refreshed_from_final_payload(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", stream=IteratorStream(_responses_reasoning_refresh_stream()), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_model("gpt-5.5") response = model.prompt("hello", key="test") > assert response.text() == "done" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:1423: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2511: in execute stream_obj = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'hello'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = True stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________________ test_code_interpreter_multi_message_response _________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'count'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_code_interpreter_multi_message_response(httpx_mock): """Server-side tool execution interleaving multiple message output items must assemble into multiple assistant Messages.""" httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", json={ "id": "resp_multi", "object": "response", "created_at": 1, "model": "gpt-5.5", "output": [ { "type": "message", "id": "msg_1", "role": "assistant", "status": "completed", "content": [ {"type": "output_text", "text": "STEP ONE", "annotations": []} ], }, { "type": "code_interpreter_call", "id": "ci_1", "status": "completed", "container_id": "cntr_1", "code": "print(111*111)", "outputs": [{"type": "logs", "logs": "12321\n"}], }, { "type": "message", "id": "msg_2", "role": "assistant", "status": "completed", "content": [ {"type": "output_text", "text": "DONE 12321", "annotations": []} ], }, ], "usage": {"input_tokens": 5, "output_tokens": 3, "total_tokens": 8}, "status": "completed", }, headers={"Content-Type": "application/json"}, ) model = llm.get_model("gpt-5.5") response = model.prompt("count", stream=False, key="test") > response.text() tests/test_openai_responses.py:1488: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2636: in execute completion = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...], 'input': [{'role': 'user', 'content': 'count'}], 'reasoning': {'summary': 'auto'}, 'store': False}, extra_json=None) stream = False stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ______________ test_code_interpreter_streaming_output_and_request ______________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ry': 'auto'}, 'store': False, 'tools': [{'type': 'code_interpreter', 'container': {'type': 'auto'}}]}, extra_json=None) stream = True stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_code_interpreter_streaming_output_and_request(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", stream=IteratorStream(_code_interpreter_stream()), headers={"Content-Type": "text/event-stream"}, ) model = llm.get_model("gpt-5.6-luna") response = model.prompt("Calculate", tools=[CodeInterpreter()], key="test") > events = list(response.stream_events()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_responses.py:1521: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2099: in stream_events for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2511: in execute stream_obj = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...ry': 'auto'}, 'store': False, 'tools': [{'type': 'code_interpreter', 'container': {'type': 'auto'}}]}, extra_json=None) stream = True stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ____________ test_web_search_streaming_refreshes_from_final_payload ____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...nt': 'Search'}], 'reasoning': {'summary': 'auto'}, 'store': False, 'tools': [{'type': 'web_search'}]}, extra_json=None) stream = True stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = def test_web_search_streaming_refreshes_from_final_payload(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", stream=IteratorStream(_web_search_refresh_stream()), headers={"Content-Type": "text/event-stream"}, ) response = llm.get_model("gpt-5.6-luna").prompt( "Search", tools=[WebSearch(include_sources=True, include_results=True)], key="test", ) > assert response.text() == "done" ^^^^^^^^^^^^^^^ tests/test_openai_responses.py:1571: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2511: in execute stream_obj = client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:1055: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...nt': 'Search'}], 'reasoning': {'summary': 'auto'}, 'store': False, 'tools': [{'type': 'web_search'}]}, extra_json=None) stream = True stream_cls = openai.Stream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai.type...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError _________ test_async_web_search_streaming_refreshes_from_final_payload _________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:388: in handle_async_request resp = await self._pool.handle_async_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:242: in handle_async_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_async/connection_pool.py:224: in handle_async_request response = await connection.handle_async_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:94: in handle_async_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:74: in handle_async_request stream = await self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_async/connection.py:117: in _connect stream = await self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/auto.py:31: in connect_tcp return await self._backend.connect_tcp( /usr/lib/python3.15/site-packages/httpcore2/_backends/anyio.py:115: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...nt': 'Search'}], 'reasoning': {'summary': 'auto'}, 'store': False, 'tools': [{'type': 'web_search'}]}, extra_json=None) stream = True stream_cls = openai.AsyncStream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1773: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:1361: in _send_request response = await self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:1340: in _send_with_auth_retry response = await super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1690: in _send_request return await self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1818: in send response = await self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1846: in _send_handling_auth response = await self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1881: in _send_handling_redirects response = await self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1915: in _send_single_request response = await transport.handle_async_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:387: in handle_async_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: httpx_mock = @pytest.mark.asyncio async def test_async_web_search_streaming_refreshes_from_final_payload(httpx_mock): httpx_mock.add_response( method="POST", url="https://api.openai.com/v1/responses", stream=IteratorStream(_web_search_refresh_stream()), headers={"Content-Type": "text/event-stream"}, ) response = llm.get_async_model("gpt-5.6-luna").prompt( "Search", tools=[WebSearch(include_sources=True, include_results=True)], key="test", ) > assert await response.text() == "done" ^^^^^^^^^^^^^^^^^^^^^ tests/test_openai_responses.py:1589: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2593: in text await self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2581: in _force async for chunk in self: ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2534: in __anext__ chunk = await self._generator.__anext__() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:2758: in execute stream_obj = await client.responses.create( /usr/lib/python3.15/site-packages/openai/resources/responses/responses.py:2964: in create return await self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:2053: in post return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/responses', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeout=NOT_...nt': 'Search'}], 'reasoning': {'summary': 'auto'}, 'store': False, 'tools': [{'type': 'web_search'}]}, extra_json=None) stream = True stream_cls = openai.AsyncStream[typing.Annotated[openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent | openai...seCustomToolCallInputDoneEvent, PropertyInfo(alias='None', format=None, format_template='None', discriminator='type')]] async def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we # execute it earlier while we are in an async context self._platform = await asyncify(get_platform)() cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = await self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} if self.custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(self.custom_auth) if is_httpx2_async_client(self._client) else normalize_legacy_httpx_auth(self.custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = await self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): await self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1808: APIConnectionError _____________ test_execute_prompt_with_multiple_templates_in_order _____________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ssages': [{'role': 'user', 'content': 'Be concise. Summarize this: Input text'}], 'temperature': 0.5}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: templates_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_execute_prompt_with_multi0/llm.datasette.io/templates') mocked_openai_chat = @mock.patch.dict(os.environ, {"OPENAI_API_KEY": "X"}) def test_execute_prompt_with_multiple_templates_in_order( templates_path, mocked_openai_chat ): (templates_path / "configuration.yaml").write_text( "model: gpt-4\noptions:\n temperature: 0.5", "utf-8" ) (templates_path / "instruction.yaml").write_text( "prompt: 'Summarize this: $input'", "utf-8" ) (templates_path / "wrapper.yaml").write_text( "prompt: 'Be concise. $input'", "utf-8" ) > result = CliRunner().invoke( cli, [ "--no-stream", "-t", "configuration", "-t", "instruction", "-t", "wrapper", "Input text", ], catch_exceptions=False, ) tests/test_templates.py:368: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ssages': [{'role': 'user', 'content': 'Be concise. Summarize this: Input text'}], 'temperature': 0.5}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError ___________________ test_template_respects_cli_extract_flag ____________________ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: > yield /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:98: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:245: in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:242: in handle_request raise exc from None /usr/lib/python3.15/site-packages/httpcore2/_sync/connection_pool.py:224: in handle_request response = connection.handle_request(pool_request.request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:94: in handle_request raise exc /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:74: in handle_request stream = self._connect(request) ^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_sync/connection.py:117: in _connect stream = self._network_backend.connect_tcp(**kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpcore2/_backends/sync.py:203: in connect_tcp with map_exceptions(exc_map): ^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ map = {: , : } @contextlib.contextmanager def map_exceptions(map: ExceptionMapping) -> Generator[None]: try: yield except Exception as exc: # noqa: PIE786 for from_exc, to_exc in map.items(): if isinstance(exc, from_exc): > raise to_exc(exc) from exc E httpcore2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpcore2/_exceptions.py:17: ConnectError The above exception was the direct cause of the following exception: self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: > response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) /usr/lib/python3.15/site-packages/openai/_base_client.py:1148: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/openai/_client.py:601: in _send_request response = self._send_with_auth_retry(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_client.py:580: in _send_with_auth_retry response = super()._send_request(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/_base_client.py:1069: in _send_request return self._client.send(request, stream=stream, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:980: in send response = self._send_handling_auth( /usr/lib/python3.15/site-packages/httpx2/_client.py:1008: in _send_handling_auth response = self._send_handling_redirects( /usr/lib/python3.15/site-packages/httpx2/_client.py:1043: in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_client.py:1076: in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:244: in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib64/python3.15/contextlib.py:224: in __exit__ self.gen.throw(value) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @contextlib.contextmanager def map_httpcore_exceptions() -> Generator[None]: global HTTPCORE_EXC_MAP if len(HTTPCORE_EXC_MAP) == 0: HTTPCORE_EXC_MAP = _load_httpcore_exceptions() try: yield except Exception as exc: mapped_exc = None for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): if not isinstance(exc, from_exc): continue # We want to map to the most specific exception we can find. # Eg if `exc` is an `httpcore2.ReadTimeout`, we want to map to # `httpx2.ReadTimeout`, not just `httpx2.TimeoutException`. if mapped_exc is None or issubclass(to_exc, mapped_exc): mapped_exc = to_exc if mapped_exc is None: # pragma: no cover raise message = str(exc) > raise mapped_exc(message) from exc E httpx2.ConnectError: [Errno -3] Temporary failure in name resolution /usr/lib/python3.15/site-packages/httpx2/_transports/default.py:115: ConnectError The above exception was the direct cause of the following exception: mocked_openai_chat_returning_fenced_code = templates_path = local('/tmp/pytest-of-mockbuild/pytest-0/test_template_respects_cli_ext0/llm.datasette.io/templates') def test_template_respects_cli_extract_flag( mocked_openai_chat_returning_fenced_code, templates_path ): (templates_path / "code.yaml").write_text("prompt: Write code", "utf-8") runner = CliRunner() > result = runner.invoke( cli, ["-t", "code", "-m", "gpt-4o-mini", "--key", "x", "-x"], catch_exceptions=False, ) tests/test_templates.py:474: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.15/site-packages/click/testing.py:687: in invoke return_value = cli.main(args=args or (), prog_name=prog_name, **extra) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1490: in main rv = self.invoke(ctx) ^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1970: in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:1353: in invoke return ctx.invoke(self.callback, **ctx.params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/click/core.py:907: in invoke return callback(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/cli.py:1134: in prompt text = response.text() ^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1873: in text self._force() ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:1869: in _force list(self) ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2075: in __iter__ for chunk in self._iter_events(): ^^^^^^^^^^^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/models.py:2064: in _iter_events for chunk in generator: ^^^^^^^^^ ../BUILDROOT/usr/lib/python3.15/site-packages/llm/default_plugins/openai_models.py:1459: in execute completion = client.chat.completions.create( /usr/lib/python3.15/site-packages/openai/_utils/_utils.py:298: in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.15/site-packages/openai/resources/chat/completions/completions.py:1318: in create return self._post( /usr/lib/python3.15/site-packages/openai/_base_client.py:1440: in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cast_to = options = FinalRequestOptions(method='post', url='/chat/completions', params={}, headers=NOT_GIVEN, max_retries=NOT_GIVEN, timeo...ta={'model': 'gpt-4o-mini', 'stream': False, 'messages': [{'role': 'user', 'content': 'Write code'}]}, extra_json=None) stream = False stream_cls = openai.Stream[openai.types.chat.chat_completion_chunk.ChatCompletionChunk] def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) # create a copy of the options we were given so that if the # options are mutated later & we then retry, the retries are # given the original options input_options = model_copy(options) if input_options.idempotency_key is None and input_options.method.lower() != "get": # ensure the idempotency key is reused between requests input_options.idempotency_key = self._idempotency_key() response: httpx2.Response | None = None max_retries = input_options.get_max_retries(self.max_retries) self._validate_max_retries(max_retries) retries_taken = 0 for retries_taken in range(max_retries + 1): options = model_copy(input_options) options = self._prepare_options(options) request_body_replay = _RequestBodyReplay(options) remaining_retries = max_retries - retries_taken request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} custom_auth = self._custom_auth(options.security) if custom_auth is not None: kwargs["auth"] = ( normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else normalize_legacy_httpx_auth(custom_auth) ) if options.follow_redirects is not None: kwargs["follow_redirects"] = options.follow_redirects log.debug("Sending HTTP Request: %s", get_http_method_for_logging(request.method)) response = None try: response = self._send_request( request, stream=stream or self._should_stream_response_body(request=request), **kwargs, ) except timeout_exceptions() as err: log.debug("Encountered a timeout exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising timeout error") raise APITimeoutError(request=request) from err except OpenAIError as err: # Propagate OpenAIErrors as-is, without retrying or wrapping in APIConnectionError raise err except request_exceptions() as err: log.debug("Encountered exception: %s", type(err).__name__) if remaining_retries > 0 and request_body_replay.rewind(): self._sleep_for_retry( retries_taken=retries_taken, max_retries=max_retries, options=input_options, response=None, ) continue log.debug("Raising connection error") > raise APIConnectionError(request=request) from err E openai.APIConnectionError: Connection error. /usr/lib/python3.15/site-packages/openai/_base_client.py:1183: APIConnectionError =============================== warnings summary =============================== tests/test_llm.py: 15 warnings /builddir/build/BUILD/python-llm-0.34-build/llm-0.34/tests/test_llm.py:1071: DeprecationWarning: 'maxsplit' is passed as positional argument declared.add(normalize(re.split(r"[<>=!~;\s\[]", requirement, 1)[0])) -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html =========================== short test summary info ============================ FAILED tests/test_cli_openai_models.py::test_gpt5_verbosity_option_is_sent_to_openai_chat_completions FAILED tests/test_cli_openai_models.py::test_gpt5_verbosity_option_is_sent_to_openai_responses_by_default FAILED tests/test_cli_openai_models.py::test_code_interpreter_cli_tool_is_resolved_from_model FAILED tests/test_cli_openai_models.py::test_code_interpreter_cli_tool_is_reused_on_continue FAILED tests/test_cli_openai_models.py::test_web_search_cli_tool_is_resolved_from_model FAILED tests/test_cli_openai_models.py::test_openai_image_detail_option_is_sent_on_image_attachments FAILED tests/test_cli_openai_models.py::test_openai_image_detail_original_is_sent_for_gpt54 FAILED tests/test_cli_openai_models.py::test_openai_image_detail_original_is_sent_for_gpt54_responses_by_default FAILED tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[None-False] FAILED tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[None-True] FAILED tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[-u-False] FAILED tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[-u-True] FAILED tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[--usage-False] FAILED tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[--usage-True] FAILED tests/test_keys.py::test_uses_correct_key - openai.APIConnectionError:... FAILED tests/test_llm.py::test_llm_prompt_creates_log_database[False] - opena... FAILED tests/test_llm.py::test_llm_prompt_creates_log_database[True] - openai... FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args0-False-True] FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args0-False-False] FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args0-False-split] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args1-True-True] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args1-True-False] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args1-True-split] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args2-False-True] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args2-False-False] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args2-False-split] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args3-True-True] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args3-True-False] FAILED tests/test_llm.py::test_llm_default_prompt[False-logs_args3-True-split] FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args4-False-True] FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args4-False-False] FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args4-False-split] FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args5-True-True] FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args5-True-False] FAILED tests/test_llm.py::test_llm_default_prompt[True-logs_args5-True-split] FAILED tests/test_llm.py::test_llm_prompt_continue[False] - openai.APIConnect... FAILED tests/test_llm.py::test_llm_prompt_continue[True] - openai.APIConnecti... FAILED tests/test_llm.py::test_extract_fenced_code[args0-True] - openai.APICo... FAILED tests/test_llm.py::test_extract_fenced_code[args1-True] - openai.APICo... FAILED tests/test_llm.py::test_extract_fenced_code[args2-True] - openai.APICo... FAILED tests/test_llm.py::test_extract_fenced_code[args3-True] - openai.APICo... FAILED tests/test_llm.py::test_extract_fenced_code[args4-False] - openai.APIC... FAILED tests/test_llm.py::test_extract_fenced_code_crlf - openai.APIConnectio... FAILED tests/test_llm.py::test_openai_chat_stream - AssertionError: assert 1 ... FAILED tests/test_llm.py::test_openai_completion - openai.APIConnectionError:... FAILED tests/test_llm.py::test_openai_completion_continue_includes_history - ... FAILED tests/test_llm.py::test_openai_completion_logprobs_stream - openai.API... FAILED tests/test_llm.py::test_openai_completion_logprobs_nostream - openai.A... FAILED tests/test_llm.py::test_openai_localai_configuration - AssertionError:... FAILED tests/test_llm.py::test_llm_prompt_continue_with_database[False] - ope... FAILED tests/test_llm.py::test_llm_prompt_continue_with_database[True] - open... FAILED tests/test_openai_endpoint.py::test_endpoint_chat_completions_does_not_log_or_leak_default_key FAILED tests/test_openai_endpoint.py::test_endpoint_chat_completions_attachment FAILED tests/test_openai_endpoint.py::test_endpoint_template - openai.APIConn... FAILED tests/test_openai_endpoint.py::test_endpoint_template_schema_object_used_when_no_cli_schema FAILED tests/test_openai_endpoint.py::test_endpoint_schema - openai.APIConnec... FAILED tests/test_openai_endpoint.py::test_endpoint_schema_by_id_from_existing_logs_database FAILED tests/test_openai_endpoint.py::test_endpoint_static_template_runs_once_on_terminal FAILED tests/test_openai_endpoint.py::test_endpoint_tools_and_functions - ope... FAILED tests/test_openai_endpoint.py::test_endpoint_streams_by_default - open... FAILED tests/test_openai_endpoint.py::test_endpoint_uses_explicit_key - opena... FAILED tests/test_openai_endpoint.py::test_endpoint_lists_models_without_model_or_logging FAILED tests/test_openai_endpoint.py::test_endpoint_models_surfaces_error_from_successful_response FAILED tests/test_openai_endpoint.py::test_endpoint_responses_api - openai.AP... FAILED tests/test_openai_endpoint.py::test_endpoint_responses_reasoning_summary_option[auto] FAILED tests/test_openai_endpoint.py::test_endpoint_responses_reasoning_summary_option[concise] FAILED tests/test_openai_endpoint.py::test_endpoint_responses_reasoning_summary_option[detailed] FAILED tests/test_openai_endpoint.py::test_endpoint_responses_api_attachment FAILED tests/test_openai_endpoint.py::test_endpoint_responses_api_schema_multi FAILED tests/test_openai_endpoint.py::test_endpoint_responses_api_tools - ope... FAILED tests/test_openai_endpoint.py::test_endpoint_responses_api_raw_server_side_tool FAILED tests/test_openai_endpoint.py::test_endpoint_reads_one_off_prompt_from_stdin FAILED tests/test_openai_endpoint.py::test_endpoint_without_prompt_waits_for_stdin FAILED tests/test_openai_endpoint.py::test_endpoint_interactive_chat_preserves_history FAILED tests/test_openai_messages.py::TestBuildMessagesConversationHistory::test_no_double_emission_from_conversation_prompt_flow FAILED tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_text_stream_yields_text_events FAILED tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_text_stream_plain_iteration_still_returns_strings FAILED tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_text_stream_messages_assembled FAILED tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_tool_call_stream_yields_name_and_args_events FAILED tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_tool_call_registered_via_add_tool_call FAILED tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_text_then_tool_call_part_index_advances FAILED tests/test_openai_messages.py::TestAsyncStreamingExecuteYieldsStreamEvents::test_text_stream_yields_text_events FAILED tests/test_openai_messages.py::TestReasoningTokenCount::test_redacted_reasoning_part_emitted_when_count_present FAILED tests/test_openai_messages.py::TestReasoningTokenCount::test_no_reasoning_part_when_zero_or_absent FAILED tests/test_openai_messages.py::TestNonStreamingExecuteYieldsStreamEvents::test_non_streaming_text_yields_single_event FAILED tests/test_openai_responses.py::test_responses_web_search_request_and_result_capture FAILED tests/test_openai_responses.py::test_responses_mixes_function_and_code_interpreter_tools FAILED tests/test_openai_responses.py::test_responses_raw_server_tool_passthrough_on_custom_endpoint FAILED tests/test_openai_responses.py::test_async_responses_code_interpreter_request FAILED tests/test_openai_responses.py::test_async_responses_web_search_request FAILED tests/test_openai_responses.py::test_chat_completions_opt_out_dispatches_to_chat FAILED tests/test_openai_responses.py::test_default_routes_to_responses_endpoint FAILED tests/test_openai_responses.py::test_hide_reasoning_omits_reasoning_summary_from_responses_request FAILED tests/test_openai_responses.py::test_non_reasoning_responses_model_omits_encrypted_reasoning_include FAILED tests/test_openai_responses.py::test_responses_reply_sends_prior_assistant_text_as_string FAILED tests/test_openai_responses.py::test_service_tier_sent_to_responses_endpoint FAILED tests/test_openai_responses.py::test_service_tier_sent_to_chat_completions_fallback FAILED tests/test_openai_responses.py::test_responses_streams_reasoning_summary_text FAILED tests/test_openai_responses.py::test_responses_reasoning_metadata_refreshed_from_final_payload FAILED tests/test_openai_responses.py::test_code_interpreter_multi_message_response FAILED tests/test_openai_responses.py::test_code_interpreter_streaming_output_and_request FAILED tests/test_openai_responses.py::test_web_search_streaming_refreshes_from_final_payload FAILED tests/test_openai_responses.py::test_async_web_search_streaming_refreshes_from_final_payload FAILED tests/test_templates.py::test_execute_prompt_with_multiple_templates_in_order FAILED tests/test_templates.py::test_template_respects_cli_extract_flag - ope... ERROR tests/test_cli_openai_models.py::test_gpt5_verbosity_option_is_sent_to_openai_chat_completions ERROR tests/test_cli_openai_models.py::test_gpt5_verbosity_option_is_sent_to_openai_responses_by_default ERROR tests/test_cli_openai_models.py::test_code_interpreter_cli_tool_is_resolved_from_model ERROR tests/test_cli_openai_models.py::test_code_interpreter_cli_tool_is_reused_on_continue ERROR tests/test_cli_openai_models.py::test_web_search_cli_tool_is_resolved_from_model ERROR tests/test_cli_openai_models.py::test_openai_image_detail_option_is_sent_on_image_attachments ERROR tests/test_cli_openai_models.py::test_openai_image_detail_original_is_sent_for_gpt54 ERROR tests/test_cli_openai_models.py::test_openai_image_detail_original_is_sent_for_gpt54_responses_by_default ERROR tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[None-False] ERROR tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[None-True] ERROR tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[-u-False] ERROR tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[-u-True] ERROR tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[--usage-False] ERROR tests/test_cli_openai_models.py::test_gpt4o_mini_sync_and_async[--usage-True] ERROR tests/test_keys.py::test_uses_correct_key - AssertionError: The followi... ERROR tests/test_llm.py::test_llm_prompt_creates_log_database[False] - Assert... ERROR tests/test_llm.py::test_llm_prompt_creates_log_database[True] - Asserti... ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args0-False-True] ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args0-False-False] ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args0-False-split] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args1-True-True] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args1-True-False] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args1-True-split] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args2-False-True] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args2-False-False] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args2-False-split] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args3-True-True] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args3-True-False] ERROR tests/test_llm.py::test_llm_default_prompt[False-logs_args3-True-split] ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args4-False-True] ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args4-False-False] ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args4-False-split] ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args5-True-True] ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args5-True-False] ERROR tests/test_llm.py::test_llm_default_prompt[True-logs_args5-True-split] ERROR tests/test_llm.py::test_llm_prompt_continue[False] - AssertionError: Th... ERROR tests/test_llm.py::test_llm_prompt_continue[True] - AssertionError: The... ERROR tests/test_llm.py::test_extract_fenced_code[args0-True] - AssertionErro... ERROR tests/test_llm.py::test_extract_fenced_code[args1-True] - AssertionErro... ERROR tests/test_llm.py::test_extract_fenced_code[args2-True] - AssertionErro... ERROR tests/test_llm.py::test_extract_fenced_code[args3-True] - AssertionErro... ERROR tests/test_llm.py::test_extract_fenced_code[args4-False] - AssertionErr... ERROR tests/test_llm.py::test_extract_fenced_code_crlf - AssertionError: The ... ERROR tests/test_llm.py::test_openai_chat_stream - AssertionError: The follow... ERROR tests/test_llm.py::test_openai_completion - AssertionError: The followi... ERROR tests/test_llm.py::test_openai_completion_continue_includes_history - A... ERROR tests/test_llm.py::test_openai_completion_logprobs_stream - AssertionEr... ERROR tests/test_llm.py::test_openai_completion_logprobs_nostream - Assertion... ERROR tests/test_llm.py::test_openai_localai_configuration - AssertionError: ... ERROR tests/test_llm.py::test_llm_prompt_continue_with_database[False] - Asse... ERROR tests/test_llm.py::test_llm_prompt_continue_with_database[True] - Asser... ERROR tests/test_openai_endpoint.py::test_endpoint_chat_completions_does_not_log_or_leak_default_key ERROR tests/test_openai_endpoint.py::test_endpoint_chat_completions_attachment ERROR tests/test_openai_endpoint.py::test_endpoint_template - AssertionError:... ERROR tests/test_openai_endpoint.py::test_endpoint_template_schema_object_used_when_no_cli_schema ERROR tests/test_openai_endpoint.py::test_endpoint_schema - AssertionError: T... ERROR tests/test_openai_endpoint.py::test_endpoint_schema_by_id_from_existing_logs_database ERROR tests/test_openai_endpoint.py::test_endpoint_static_template_runs_once_on_terminal ERROR tests/test_openai_endpoint.py::test_endpoint_tools_and_functions - Asse... ERROR tests/test_openai_endpoint.py::test_endpoint_streams_by_default - Asser... ERROR tests/test_openai_endpoint.py::test_endpoint_uses_explicit_key - Assert... ERROR tests/test_openai_endpoint.py::test_endpoint_lists_models_without_model_or_logging ERROR tests/test_openai_endpoint.py::test_endpoint_models_surfaces_error_from_successful_response ERROR tests/test_openai_endpoint.py::test_endpoint_responses_api - AssertionE... ERROR tests/test_openai_endpoint.py::test_endpoint_responses_reasoning_summary_option[auto] ERROR tests/test_openai_endpoint.py::test_endpoint_responses_reasoning_summary_option[concise] ERROR tests/test_openai_endpoint.py::test_endpoint_responses_reasoning_summary_option[detailed] ERROR tests/test_openai_endpoint.py::test_endpoint_responses_api_attachment ERROR tests/test_openai_endpoint.py::test_endpoint_responses_api_schema_multi ERROR tests/test_openai_endpoint.py::test_endpoint_responses_api_tools - Asse... ERROR tests/test_openai_endpoint.py::test_endpoint_responses_api_raw_server_side_tool ERROR tests/test_openai_endpoint.py::test_endpoint_reads_one_off_prompt_from_stdin ERROR tests/test_openai_endpoint.py::test_endpoint_without_prompt_waits_for_stdin ERROR tests/test_openai_endpoint.py::test_endpoint_interactive_chat_preserves_history ERROR tests/test_openai_messages.py::TestBuildMessagesConversationHistory::test_no_double_emission_from_conversation_prompt_flow ERROR tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_text_stream_yields_text_events ERROR tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_text_stream_plain_iteration_still_returns_strings ERROR tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_text_stream_messages_assembled ERROR tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_tool_call_stream_yields_name_and_args_events ERROR tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_tool_call_registered_via_add_tool_call ERROR tests/test_openai_messages.py::TestStreamingExecuteYieldsStreamEvents::test_text_then_tool_call_part_index_advances ERROR tests/test_openai_messages.py::TestAsyncStreamingExecuteYieldsStreamEvents::test_text_stream_yields_text_events ERROR tests/test_openai_messages.py::TestReasoningTokenCount::test_redacted_reasoning_part_emitted_when_count_present ERROR tests/test_openai_messages.py::TestReasoningTokenCount::test_no_reasoning_part_when_zero_or_absent ERROR tests/test_openai_messages.py::TestNonStreamingExecuteYieldsStreamEvents::test_non_streaming_text_yields_single_event ERROR tests/test_openai_responses.py::test_responses_web_search_request_and_result_capture ERROR tests/test_openai_responses.py::test_responses_mixes_function_and_code_interpreter_tools ERROR tests/test_openai_responses.py::test_responses_raw_server_tool_passthrough_on_custom_endpoint ERROR tests/test_openai_responses.py::test_async_responses_code_interpreter_request ERROR tests/test_openai_responses.py::test_async_responses_web_search_request ERROR tests/test_openai_responses.py::test_chat_completions_opt_out_dispatches_to_chat ERROR tests/test_openai_responses.py::test_default_routes_to_responses_endpoint ERROR tests/test_openai_responses.py::test_hide_reasoning_omits_reasoning_summary_from_responses_request ERROR tests/test_openai_responses.py::test_non_reasoning_responses_model_omits_encrypted_reasoning_include ERROR tests/test_openai_responses.py::test_responses_reply_sends_prior_assistant_text_as_string ERROR tests/test_openai_responses.py::test_service_tier_sent_to_responses_endpoint ERROR tests/test_openai_responses.py::test_service_tier_sent_to_chat_completions_fallback ERROR tests/test_openai_responses.py::test_responses_streams_reasoning_summary_text ERROR tests/test_openai_responses.py::test_responses_reasoning_metadata_refreshed_from_final_payload ERROR tests/test_openai_responses.py::test_code_interpreter_multi_message_response ERROR tests/test_openai_responses.py::test_code_interpreter_streaming_output_and_request ERROR tests/test_openai_responses.py::test_web_search_streaming_refreshes_from_final_payload ERROR tests/test_openai_responses.py::test_async_web_search_streaming_refreshes_from_final_payload ERROR tests/test_templates.py::test_execute_prompt_with_multiple_templates_in_order ERROR tests/test_templates.py::test_template_respects_cli_extract_flag - Asse... = 105 failed, 982 passed, 37 skipped, 15 warnings, 105 errors in 201.69s (0:03:21) = RPM build errors: error: Bad exit status from /var/tmp/rpm-tmp.rpvEvt (%check) Bad exit status from /var/tmp/rpm-tmp.rpvEvt (%check) Finish: rpmbuild python-llm-0.34-1.fc46.src.rpm Finish: build phase for python-llm-0.34-1.fc46.src.rpm INFO: chroot_scan: 1 files copied to /var/lib/copr-rpmbuild/results/chroot_scan INFO: /var/lib/mock/fedora-rawhide-x86_64-1791974115.829543/root/var/log/dnf5.log INFO: chroot_scan: creating tarball /var/lib/copr-rpmbuild/results/chroot_scan.tar.gz /bin/tar: Removing leading `/' from member names ERROR: Exception(/var/lib/copr-rpmbuild/results/python-llm-0.34-1.fc46.src.rpm) Config(fedora-rawhide-x86_64) 3 minutes 39 seconds INFO: Results and/or logs in: /var/lib/copr-rpmbuild/results INFO: Cleaning up build root ('cleanup_on_failure=True') Start: clean chroot INFO: unmounting tmpfs. Finish: clean chroot ERROR: Command failed: # /usr/bin/systemd-nspawn -q -M 6af1b93da1ee4f7898fd4d065acdb8b2 -D /var/lib/mock/fedora-rawhide-x86_64-1791974115.829543/root -a -u mockbuild --capability=cap_ipc_lock --capability=cap_ipc_lock --bind=/dev/btrfs-control --bind=/dev/mapper/control --bind=/dev/fuse --bind=/dev/loop-control --bind=/dev/loop0 --bind=/dev/loop1 --bind=/dev/loop2 --bind=/dev/loop3 --bind=/dev/loop4 --bind=/dev/loop5 --bind=/dev/loop6 --bind=/dev/loop7 --bind=/dev/loop8 --bind=/dev/loop9 --bind=/dev/loop10 --bind=/dev/loop11 --resolv-conf=off --resolv-conf=off --console=pipe --setenv=TERM=vt100 --setenv=SHELL=/bin/bash --setenv=HOME=/builddir --setenv=HOSTNAME=mock --setenv=PATH=/usr/bin:/bin:/usr/sbin:/sbin '--setenv=PROMPT_COMMAND=printf "\033]0;\007"' '--setenv=PS1= \s-\v\$ ' --setenv=LANG=C.UTF-8 bash --login -c '/usr/bin/rpmbuild -ba --noprep --noclean --target x86_64 /builddir/build/originals/python-llm.spec' Copr build error: Build failed