Gevent: Socks5 proxy and gevent error AttributeError: 'super' object has no attribute 'getpeername'

Created on 8 Feb 2017  路  7Comments  路  Source: gevent/gevent

same problem after update

urllib

from gevent import monkey
monkey.patch_all()

import urllib.request
import socks
from sockshandler import SocksiPyHandler

request = urllib.request.Request('http://myip.dnsomatic.com')
opener = urllib.request.build_opener(SocksiPyHandler(socks.SOCKS5, '127.0.0.1', 9050))
urllib.request.install_opener(opener)

handle = urllib.request.urlopen(request, timeout=60)
print(handle.read())
Traceback (most recent call last):

https://github.com/Anorov/PySocks/issues/65

Most helpful comment

I also encountered this problem, and I really want to use gevent with PySocks so I looked into the problem a bit. Here are my findings...

  1. The error only occurs with HTTP urls, not HTTPS

  2. _BaseSocket class from PySocks inherited from socket.socket, which is monkey patched by gevent(?) and it is missing the getpeername() method which exists on the original socket class in the standard library.

I got PySocks to work with gevent by making the following changes in PySocks

    def get_proxy_peername(self):
        """
        Returns the IP and port number of the proxy.
        """
        # return super(socksocket, self).getpeername()
        return self.getpeername()

I am not too sure if this has other side effects or maybe this is the wrong way to fix the problem..

All 7 comments

Ah, hmm. This appears to be a limitation of super that I hadn't really thought about/encountered before:

Note that super() is implemented as part of the binding process for explicit dotted attribute lookups such as super().__getitem__(name). It does so by implementing its own __getattribute__() method for searching classes in a predictable order that supports cooperative multiple inheritance. Accordingly, super() is undefined for implicit lookups using statements or operators such as super()[name].

The implication being that if the class also defines a __getattr__ or __getattribute__, then super won't work as expected. :/

Without having given it much thought, my next suggestion would be for PySocks to avoid subclassing the socket and delegate to it instead, much like gevent does. There are a bunch of workarounds in PySocks to make subclassing a socket work, but it's not clear that socket objects are really meant to be subclassed (indeed, the documentation only refers to socket.socket as a function, not a class. (In fact at one time gevent did subclass the socket, but that had so many portability issues that delegation turned out to be the better---only---option, IIRC)

It's not clear to me that there's anything gevent can or should do here.

I also encountered this problem, and I really want to use gevent with PySocks so I looked into the problem a bit. Here are my findings...

  1. The error only occurs with HTTP urls, not HTTPS

  2. _BaseSocket class from PySocks inherited from socket.socket, which is monkey patched by gevent(?) and it is missing the getpeername() method which exists on the original socket class in the standard library.

I got PySocks to work with gevent by making the following changes in PySocks

    def get_proxy_peername(self):
        """
        Returns the IP and port number of the proxy.
        """
        # return super(socksocket, self).getpeername()
        return self.getpeername()

I am not too sure if this has other side effects or maybe this is the wrong way to fix the problem..

@ianchen06 I can confirm that using self works. Would you mind to create a PR to PySocks?

@jamadden How to proceed here?

AFAICS changes need to be made in pysocks (note that this change can easily be applied by users with their own monkey-patch). I don't see gevent manually copying wrappers for every stdlib function into its class; we only do that when necessary for gevent functionality as its a maintenance burden.

@jamadden Can you elaborate on the changes that should be applied to PySocks? Sorry, if this is a stupid question. I'm confused by this thread which points to PySocks and related threads in PySocks which claim that it is not a PySocks issue.

I did a couple of weeks hacking on a fast parallel upload tool with gevent, but now see that it is not working in company environment which requires to go over a socks5 proxy.

I made it work following the recommendation from @ianchen06, but patching PySocks manually seems inappropriate for me. (Especially because I don't know if replacing super by self is really the way to go)

Upstream has fixed this in https://github.com/Anorov/PySocks/pull/88 and closed the original issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sachinpkale picture sachinpkale  路  7Comments

aelse picture aelse  路  8Comments

jamadden picture jamadden  路  6Comments

jamadden picture jamadden  路  9Comments

MuslimBeibytuly picture MuslimBeibytuly  路  3Comments