from urllib.request import ProxyHandler, build_opener

def make_proxy_opener(proxy_uri):
    return build_opener(ProxyHandler({
        "http": proxy_uri,
        "https": proxy_uri,
    }))

opener = make_proxy_opener("http://proxy.example.net:8080")
# Use opener.open(destination, timeout=10) for this route.

Call this opener's own open method when a route belongs to the probe. The example's HTTP endpoint may come from your service or the HTTP proxy list for public probes. The fragment illustrates ownership; it does not define the full authentication or health policy. Keep any account-specific handlers attached to that intended client.

urllib.request.install_opener() changes the process-wide default used by later module-level urlopen() calls. A checker looping through proxies can therefore leave unrelated requests using its last endpoint. Installing temporarily and restoring in cleanup still permits concurrent requests to run during the shared mutation.

socket.setdefaulttimeout() similarly changes defaults for subsequently created sockets. Use the operation-level timeout when only the probe should receive it.

Close probe responses and keep their results specific: an HTTP error response is not automatically a dead proxy listener. If a synchronous urllib probe is used in an async service, move blocking work to an appropriate worker; that execution decision does not make global opener mutation isolated.

A probe should return its observation without leaving another network policy behind. Its own client object and bounded operation make that boundary explicit.

Allakkat attuumassuteqartut