Replace unmaintained httpretty with mocket in the test suite
@mconflitti-pbc arbeitet bereits daran.
Seit 07.8.2026.
Bewertung
Dieses Issue wurde noch nicht bewertet.
Beschreibung
Problem
Adding Python 3.14 support required a shim in conftest.py, because httpretty
fails on 3.14. This ticket proposes removing that shim by replacing httpretty
with a maintained equivalent.
Root cause
CPython 3.14 makes functools.partial objects method descriptors. A
FutureWarning was added in 3.13 (python/cpython#121027) and the behavior
changed in 3.14 (python/cpython#125983):
3.13: class C: m = partial(f, "PRE") -> C().m("SOCK") == ("PRE", "SOCK") + FutureWarning
3.14: class C: m = partial(f, "PRE") -> C().m("SOCK") == ("PRE", <C obj>, "SOCK")
httpretty mocks TLS with this class-attribute assignment
(httpretty/core.py:1875):
ssl.SSLContext.wrap_socket = partial(fake_wrap_socket, old_ssl_wrap_socket)
On 3.14 the partial now binds, so the SSLContext arrives as the first
positional argument and httpretty mistakes it for the socket. Every HTTPS test
fails with:
AttributeError: 'SSLContext' object has no attribute 'sendall'
That is 3 tests today (the shinyapps.io paths in tests/test_main.py), but it
affects the whole TLS mock, which covers over 100 https:// registrations.
Upstream will probably not fix this
- gabrielfalcao/HTTPretty#488 ("Support Python 3.14 partial() changes", opened
2026-04-10) fixes it withstaticmethod(partial(...)), but is unmerged. - httpretty 1.1.4 was released 2021-08-16. The last merged PR was 2022-10-11.
There are 129 open issues, with PRs from 2023 and 2024 still open. The PyPI
classifiers stop at Python 3.9. - Even a released upstream fix may not help us:
staticmethodobjects only
became callable in Python 3.10, so #488's two module-level assignments
(ssl.wrap_socketandrequests_urllib3_connection.ssl_wrap_socket) would
break on our 3.8 and 3.9 floor if anything called them.
Current workaround
conftest.py wraps httpretty.core.fake_wrap_socket and drops the leading
SSLContext. It is 4 lines and verified on 3.8, 3.13 and 3.14, and it stays
correct if #488 lands (the isinstance check simply stops matching).
Its downside: it reads a private function at import time. If httpretty renames
fake_wrap_socket, the failure is not one red test. Collection fails and the
entire suite stops on every Python version and OS.
Proposal: migrate to mocket
mocket 3.14.3 (uploaded
2026-07-13) is actively maintained, declares requires-python = ">=3.8", and
classifies 3.8 through 3.14, so it covers our full support range. Its major
version tracks the newest supported Python.
Verified against rsconnect's real http.client HTTPS path on 3.14 using
mocket.plugins.httpretty: status 200 and the JSON body came back intact with
strict_mode=True.
Note the honest limits:
- mocket monkeypatches
socketandssltoo. This buys a maintainer, not real
TLS. Only a real local server (for examplepytest-httpserver) would give
real TLS, at the cost of rewriting all registrations and adding certificate
plumbing. responsesandrequests-mockare not options. rsconnect useshttp.client
directly (rsconnect/http_support.py), notrequests.
Migration scope
6 test files: test_api.py, test_main.py, test_main_content.py,
test_main_environment.py, test_main_integration.py,
test_main_system_caches.py.
| Item | Count | Notes |
|---|---|---|
@httpretty.activate(verbose=True, allow_net_connect=False) |
81 | becomes @mocketize(strict_mode=True); verbose has no equivalent |
httpretty.register_uri(...) |
165 | body, adding_headers and status confirmed working |
latest_requests() / last_request() |
17 | attributes in mocket, not calls; verify .method, .path, .body parity |
has_request |
1 | no equivalent; needs a manual replacement |
Acceptance criteria
- The
fake_wrap_socketshim is deleted fromconftest.py. - The suite is green on Python 3.8 through 3.14.
- Test count and skip count are unchanged (768 passed, 12 skipped today).
- Line coverage does not regress (83.0% today).
Context
Closed #528 is where this repo deliberately adopted httpretty over
mock_connect, so that trade-off is worth re-reading before changing direction.
Separate pre-existing gap, unchanged by any of the above and out of scope here:
the custom-CA branch (ssl.create_default_context(cadata=...)) and the
--insecure branch (ssl._create_unverified_context()) in
rsconnect/http_support.py are not covered by the httpretty tests on any
Python version.
- Vorherrschende Sprache
- Python
- Sterne
- 37
- Forks
- 28
- Ø Merge
- 1 T. 3 Std.
- Gemergte PRs (30 T.)
- 7
Entwicklungsumgebung
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus posit-dev/rsconnect-python
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
posit-dev/rsconnect-python#786 · 1 Reaktion ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 62/100
posit-dev/rsconnect-python#543 · 2 Kommentare ·
-
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 72/100
posit-dev/rsconnect-python#513 ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 65/100
posit-dev/rsconnect-python#178 ·
-
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 58/100
posit-dev/rsconnect-python#855 ·
Alle Issues in posit-dev/rsconnect-python
Ähnliche Issues
-
bug status/needs-triage
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 86/100
prowler-cloud/prowler#12887 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
area: desktop platform: macos priority: p3 status: ready type: enhancement
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 92/100
use-agent-os/agent-os#3484 ·
Maintainer antworten meist innerhalb von 2 Tagen
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 86/100
open-telemetry/opentelemetry-python-contrib#5113 · 2 Kommentare · 2 Reaktionen ·
Maintainer antworten meist innerhalb von 1 Tag
-
external
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
langchain-ai/docs#6255 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
Maintainer antworten meist innerhalb von 1 Tag