socket: Actually provide non-blocking DNS methods

The green socket module seemed to have only blocking DNS resolution
methods even with dnspython installed which is inconsistent with the
documentation.

This patch has a few consequences:

* an import cycle is eliminated
* if an import cycle reappears here it'll be visible

Note: eliminating the import cycle revealed an issue related to monkey
patching and the way we perform greendns tests (the test failures were
already present on Python 3.5[1] as that version has some import cycle
handling changes). The failures look like this:

======================================================================
FAIL: test_query_ans_types (tests.greendns_test.TestHostsResolver)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kuba/projects/eventlet/tests/greendns_test.py", line 97, in test_query_ans_types
    assert isinstance(ans, greendns.dns.resolver.Answer)
AssertionError

======================================================================
FAIL: test_query_unknown_no_raise (tests.greendns_test.TestHostsResolver)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kuba/projects/eventlet/tests/greendns_test.py", line 129, in test_query_unknown_no_raise
    assert isinstance(ans, greendns.dns.resolver.Answer)
AssertionError

This issue will be addressed in a separate commit.

This patch is contributed by Smarkets Limited.

[1] https://github.com/eventlet/eventlet/issues/267
This commit is contained in:
Jakub Stasiak
2016-05-17 21:16:58 +02:00
parent 7e1dc8a1a5
commit 861d684399
3 changed files with 32 additions and 5 deletions

View File

@@ -16,7 +16,16 @@ if os.environ.get("EVENTLET_NO_GREENDNS", '').lower() != "yes":
try:
from eventlet.support import greendns
except ImportError as ex:
pass
try:
import dns
except ImportError:
# greendns import failed because we don't have dnspython - all is well,
# that's why we have the conditional import
pass
else:
# If, however, dnspython is importable yet greendns can't be imported
# this suggests there's another issue (like an import cycle)
raise
if greendns:
gethostbyname = greendns.gethostbyname

View File

@@ -43,6 +43,10 @@ from eventlet.support import six
def import_patched(module_name):
# Import cycle note: it's crucial to use _socket_nodns here because
# regular evenlet.green.socket imports *this* module and if we imported
# it back we'd end with an import cycle (socket -> greendns -> socket).
# We break this import cycle by providing a restricted socket module.
return patcher.import_patched(module_name,
select=select,
time=time,
@@ -55,15 +59,15 @@ dns.resolver = import_patched('dns.resolver')
for pkg in ('dns.entropy', 'dns.inet', 'dns.query'):
setattr(dns, pkg.split('.')[1], import_patched(pkg))
del import_patched
import dns.rdtypes
for pkg in ['dns.rdtypes.IN', 'dns.rdtypes.ANY']:
setattr(dns.rdtypes, pkg.split('.')[-1], patcher.import_patched(pkg))
setattr(dns.rdtypes, pkg.split('.')[-1], import_patched(pkg))
for pkg in ['dns.rdtypes.IN.A', 'dns.rdtypes.IN.AAAA']:
setattr(dns.rdtypes.IN, pkg.split('.')[-1], patcher.import_patched(pkg))
setattr(dns.rdtypes.IN, pkg.split('.')[-1], import_patched(pkg))
for pkg in ['dns.rdtypes.ANY.CNAME']:
setattr(dns.rdtypes.ANY, pkg.split('.')[-1], patcher.import_patched(pkg))
setattr(dns.rdtypes.ANY, pkg.split('.')[-1], import_patched(pkg))
del import_patched
socket = _socket_nodns

View File

@@ -1,5 +1,11 @@
import eventlet
from eventlet.green import socket
try:
from eventlet.support import greendns
has_greendns = True
except ImportError:
has_greendns = False
from tests import skip_if
def test_create_connection_error():
@@ -29,3 +35,11 @@ def test_recv_type():
sock = eventlet.connect(tuple(addr))
s = sock.recv(1)
assert isinstance(s, bytes)
@skip_if(not has_greendns)
def test_dns_methods_are_green():
assert socket.gethostbyname is greendns.gethostbyname
assert socket.gethostbyname_ex is greendns.gethostbyname_ex
assert socket.getaddrinfo is greendns.getaddrinfo
assert socket.getnameinfo is greendns.getnameinfo