diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b2f4db5..0000000 --- a/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# python specific -*.pyc -*.so -*.pyd -build/* -dist/* -MANIFEST -__pycache__/ -*.egg-info/ - -# generic files to ignore -*~ -*.lock -*.DS_Store -*.swp -*.out - -.tox/ -deps/ -docs/_build/ -.mypy_cache/ diff --git a/MANIFEST.in b/MANIFEST.in index 63f6a19..cd1f40e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ include README.rst LICENSE ChangeLog include setup.py tests.py +include aiodns/py.typed recursive-exclude * __pycache__ recursive-exclude * *.py[co] diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..d3e0c26 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,126 @@ +Metadata-Version: 2.1 +Name: aiodns +Version: 3.2.0 +Summary: Simple DNS resolver for asyncio +Home-page: https://github.com/saghul/aiodns +Author: Saúl Ibarra Corretgé +Author-email: s@saghul.net +License: MIT +Description: =============================== + Simple DNS resolver for asyncio + =============================== + + .. image:: https://badge.fury.io/py/aiodns.png + :target: https://pypi.org/project/aiodns/ + + .. image:: https://github.com/saghul/aiodns/workflows/CI/badge.svg + :target: https://github.com/saghul/aiodns/actions + + aiodns provides a simple way for doing asynchronous DNS resolutions using `pycares `_. + + + Example + ======= + + .. code:: python + + import asyncio + import aiodns + + loop = asyncio.get_event_loop() + resolver = aiodns.DNSResolver(loop=loop) + + async def query(name, query_type): + return await resolver.query(name, query_type) + + coro = query('google.com', 'A') + result = loop.run_until_complete(coro) + + + The following query types are supported: A, AAAA, ANY, CAA, CNAME, MX, NAPTR, NS, PTR, SOA, SRV, TXT. + + + API + === + + The API is pretty simple, three functions are provided in the ``DNSResolver`` class: + + * ``query(host, type)``: Do a DNS resolution of the given type for the given hostname. It returns an + instance of ``asyncio.Future``. The actual result of the DNS query is taken directly from pycares. + As of version 1.0.0 of aiodns (and pycares, for that matter) results are always namedtuple-like + objects with different attributes. Please check the `documentation + `_ + for the result fields. + * ``gethostbyname(host, socket_family)``: Do a DNS resolution for the given + hostname and the desired type of address family (i.e. ``socket.AF_INET``). + While ``query()`` always performs a request to a DNS server, + ``gethostbyname()`` first looks into ``/etc/hosts`` and thus can resolve + local hostnames (such as ``localhost``). Please check `the documentation + `_ + for the result fields. The actual result of the call is a ``asyncio.Future``. + * ``gethostbyaddr(name)``: Make a reverse lookup for an address. + * ``cancel()``: Cancel all pending DNS queries. All futures will get ``DNSError`` exception set, with + ``ARES_ECANCELLED`` errno. + + + Note for Windows users + ====================== + + This library requires the asyncio loop to be a `SelectorEventLoop`, which is not the default on Windows since + Python 3.8. + + The default can be changed as follows (do this very early in your application): + + .. code:: python + + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + + This may have other implications for the rest of your codebase, so make sure to test thoroughly. + + + Running the test suite + ====================== + + To run the test suite: ``python tests.py`` + + + Author + ====== + + Saúl Ibarra Corretgé + + + License + ======= + + aiodns uses the MIT license, check LICENSE file. + + + Python versions + =============== + + Python >= 3.6 are supported. + + + Contributing + ============ + + If you'd like to contribute, fork the project, make a patch and send a pull + request. Have a look at the surrounding code and please, make yours look + alike :-) + +Platform: POSIX +Platform: Microsoft Windows +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Description-Content-Type: text/x-rst diff --git a/README.rst b/README.rst index 900ebfd..0e0f35e 100644 --- a/README.rst +++ b/README.rst @@ -55,6 +55,21 @@ The API is pretty simple, three functions are provided in the ``DNSResolver`` cl ``ARES_ECANCELLED`` errno. +Note for Windows users +====================== + +This library requires the asyncio loop to be a `SelectorEventLoop`, which is not the default on Windows since +Python 3.8. + +The default can be changed as follows (do this very early in your application): + +.. code:: python + + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + +This may have other implications for the rest of your codebase, so make sure to test thoroughly. + + Running the test suite ====================== diff --git a/aiodns.egg-info/PKG-INFO b/aiodns.egg-info/PKG-INFO new file mode 100644 index 0000000..d3e0c26 --- /dev/null +++ b/aiodns.egg-info/PKG-INFO @@ -0,0 +1,126 @@ +Metadata-Version: 2.1 +Name: aiodns +Version: 3.2.0 +Summary: Simple DNS resolver for asyncio +Home-page: https://github.com/saghul/aiodns +Author: Saúl Ibarra Corretgé +Author-email: s@saghul.net +License: MIT +Description: =============================== + Simple DNS resolver for asyncio + =============================== + + .. image:: https://badge.fury.io/py/aiodns.png + :target: https://pypi.org/project/aiodns/ + + .. image:: https://github.com/saghul/aiodns/workflows/CI/badge.svg + :target: https://github.com/saghul/aiodns/actions + + aiodns provides a simple way for doing asynchronous DNS resolutions using `pycares `_. + + + Example + ======= + + .. code:: python + + import asyncio + import aiodns + + loop = asyncio.get_event_loop() + resolver = aiodns.DNSResolver(loop=loop) + + async def query(name, query_type): + return await resolver.query(name, query_type) + + coro = query('google.com', 'A') + result = loop.run_until_complete(coro) + + + The following query types are supported: A, AAAA, ANY, CAA, CNAME, MX, NAPTR, NS, PTR, SOA, SRV, TXT. + + + API + === + + The API is pretty simple, three functions are provided in the ``DNSResolver`` class: + + * ``query(host, type)``: Do a DNS resolution of the given type for the given hostname. It returns an + instance of ``asyncio.Future``. The actual result of the DNS query is taken directly from pycares. + As of version 1.0.0 of aiodns (and pycares, for that matter) results are always namedtuple-like + objects with different attributes. Please check the `documentation + `_ + for the result fields. + * ``gethostbyname(host, socket_family)``: Do a DNS resolution for the given + hostname and the desired type of address family (i.e. ``socket.AF_INET``). + While ``query()`` always performs a request to a DNS server, + ``gethostbyname()`` first looks into ``/etc/hosts`` and thus can resolve + local hostnames (such as ``localhost``). Please check `the documentation + `_ + for the result fields. The actual result of the call is a ``asyncio.Future``. + * ``gethostbyaddr(name)``: Make a reverse lookup for an address. + * ``cancel()``: Cancel all pending DNS queries. All futures will get ``DNSError`` exception set, with + ``ARES_ECANCELLED`` errno. + + + Note for Windows users + ====================== + + This library requires the asyncio loop to be a `SelectorEventLoop`, which is not the default on Windows since + Python 3.8. + + The default can be changed as follows (do this very early in your application): + + .. code:: python + + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + + This may have other implications for the rest of your codebase, so make sure to test thoroughly. + + + Running the test suite + ====================== + + To run the test suite: ``python tests.py`` + + + Author + ====== + + Saúl Ibarra Corretgé + + + License + ======= + + aiodns uses the MIT license, check LICENSE file. + + + Python versions + =============== + + Python >= 3.6 are supported. + + + Contributing + ============ + + If you'd like to contribute, fork the project, make a patch and send a pull + request. Have a look at the surrounding code and please, make yours look + alike :-) + +Platform: POSIX +Platform: Microsoft Windows +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Description-Content-Type: text/x-rst diff --git a/aiodns.egg-info/SOURCES.txt b/aiodns.egg-info/SOURCES.txt new file mode 100644 index 0000000..a3e6f78 --- /dev/null +++ b/aiodns.egg-info/SOURCES.txt @@ -0,0 +1,15 @@ +ChangeLog +LICENSE +MANIFEST.in +README.rst +setup.cfg +setup.py +tests.py +aiodns/__init__.py +aiodns/error.py +aiodns/py.typed +aiodns.egg-info/PKG-INFO +aiodns.egg-info/SOURCES.txt +aiodns.egg-info/dependency_links.txt +aiodns.egg-info/requires.txt +aiodns.egg-info/top_level.txt \ No newline at end of file diff --git a/aiodns.egg-info/dependency_links.txt b/aiodns.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/aiodns.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/aiodns.egg-info/requires.txt b/aiodns.egg-info/requires.txt new file mode 100644 index 0000000..123a3f0 --- /dev/null +++ b/aiodns.egg-info/requires.txt @@ -0,0 +1 @@ +pycares>=4.0.0 diff --git a/aiodns.egg-info/top_level.txt b/aiodns.egg-info/top_level.txt new file mode 100644 index 0000000..808b760 --- /dev/null +++ b/aiodns.egg-info/top_level.txt @@ -0,0 +1 @@ +aiodns diff --git a/aiodns/__init__.py b/aiodns/__init__.py index d79b655..1febf94 100644 --- a/aiodns/__init__.py +++ b/aiodns/__init__.py @@ -3,18 +3,21 @@ import functools import pycares import socket +import sys from typing import ( Any, - List, Optional, - Set + Set, + Sequence, + Tuple, + Union ) from . import error -__version__ = '3.0.0' +__version__ = '3.2.0' __all__ = ('DNSResolver', 'error') @@ -44,13 +47,27 @@ } class DNSResolver: - def __init__(self, nameservers: Optional[List[str]] = None, + def __init__(self, nameservers: Optional[Sequence[str]] = None, loop: Optional[asyncio.AbstractEventLoop] = None, **kwargs: Any) -> None: self.loop = loop or asyncio.get_event_loop() assert self.loop is not None + if sys.platform == 'win32': + if not isinstance(self.loop, asyncio.SelectorEventLoop): + try: + import winloop + if not isinstance(self.loop , winloop.Loop): + raise RuntimeError( + 'aiodns needs a SelectorEventLoop on Windows. See more: https://github.com/saghul/aiodns/issues/86') + except ModuleNotFoundError: + raise RuntimeError( + 'aiodns needs a SelectorEventLoop on Windows. See more: https://github.com/saghul/aiodns/issues/86') kwargs.pop('sock_state_cb', None) - self._channel = pycares.Channel(sock_state_cb=self._sock_state_cb, **kwargs) + timeout = kwargs.pop('timeout', None) + self._timeout = timeout + self._channel = pycares.Channel(sock_state_cb=self._sock_state_cb, + timeout=timeout, + **kwargs) if nameservers: self.nameservers = nameservers self._read_fds = set() # type: Set[int] @@ -58,11 +75,11 @@ def __init__(self, nameservers: Optional[List[str]] = None, self._timer = None # type: Optional[asyncio.TimerHandle] @property - def nameservers(self) -> pycares.Channel: + def nameservers(self) -> Sequence[str]: return self._channel.servers @nameservers.setter - def nameservers(self, value: List[str]) -> None: + def nameservers(self, value: Sequence[str]) -> None: self._channel.servers = value @staticmethod @@ -74,7 +91,7 @@ def _callback(fut: asyncio.Future, result: Any, errorno: int) -> None: else: fut.set_result(result) - def query(self, host: str, qtype: str, qclass: str=None) -> asyncio.Future: + def query(self, host: str, qtype: str, qclass: Optional[str]=None) -> asyncio.Future: try: qtype = query_type_map[qtype] except KeyError: @@ -95,6 +112,18 @@ def gethostbyname(self, host: str, family: socket.AddressFamily) -> asyncio.Futu cb = functools.partial(self._callback, fut) self._channel.gethostbyname(host, family, cb) return fut + + def getaddrinfo(self, host: str, family: socket.AddressFamily = socket.AF_UNSPEC, port: Optional[int] = None, proto: int = 0, type: int = 0, flags: int = 0) -> asyncio.Future: + fut = asyncio.Future(loop=self.loop) # type: asyncio.Future + cb = functools.partial(self._callback, fut) + self._channel.getaddrinfo(host, port, cb, family=family, type=type, proto=proto, flags=flags) + return fut + + def getnameinfo(self, sockaddr: Union[Tuple[str, int], Tuple[str, int, int, int]], flags: int = 0) -> asyncio.Future: + fut = asyncio.Future(loop=self.loop) # type: asyncio.Future + cb = functools.partial(self._callback, fut) + self._channel.getnameinfo(sockaddr, flags, cb) + return fut def gethostbyaddr(self, name: str) -> asyncio.Future: fut = asyncio.Future(loop=self.loop) # type: asyncio.Future @@ -114,7 +143,7 @@ def _sock_state_cb(self, fd: int, readable: bool, writable: bool) -> None: self.loop.add_writer(fd, self._handle_event, fd, WRITE) self._write_fds.add(fd) if self._timer is None: - self._timer = self.loop.call_later(1.0, self._timer_cb) + self._start_timer() else: # socket is now closed if fd in self._read_fds: @@ -141,6 +170,15 @@ def _handle_event(self, fd: int, event: Any) -> None: def _timer_cb(self) -> None: if self._read_fds or self._write_fds: self._channel.process_fd(pycares.ARES_SOCKET_BAD, pycares.ARES_SOCKET_BAD) - self._timer = self.loop.call_later(1.0, self._timer_cb) + self._start_timer() else: self._timer = None + + def _start_timer(self): + timeout = self._timeout + if timeout is None or timeout < 0 or timeout > 1: + timeout = 1 + elif timeout == 0: + timeout = 0.1 + + self._timer = self.loop.call_later(timeout, self._timer_cb) diff --git a/aiodns/py.typed b/aiodns/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/debian/changelog b/debian/changelog index 36bb787..8ba0c1f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,27 @@ +aiodns (3.2.0-2) unstable; urgency=medium + + * Orphan the package, see #1074759 + - Remove myself from uploaders and update maintainer to Debian QA Group + - Update Vcs-* to Debian group + + -- Scott Kitterman Tue, 02 Jul 2024 10:08:57 -0400 + +aiodns (3.2.0-1) unstable; urgency=medium + + * New upstream release + - Drop all patches, incorporated upstream + + -- Scott Kitterman Wed, 03 Apr 2024 15:46:19 -0400 + +aiodns (3.1.1-1) unstable; urgency=medium + + * Point debian/watch at pypi, since that's where the tarballs are now + * New upstream release + - Drop all patches, incorporated upstream + * Add d/p/0001-Update-address-in-test_query_ptr.patch to fix failing test + + -- Scott Kitterman Tue, 02 Jan 2024 11:40:26 -0500 + aiodns (3.0.0-2) unstable; urgency=medium * Add patch to skip test which no longer works because the domain used in diff --git a/debian/control b/debian/control index afaaeb5..da639b9 100644 --- a/debian/control +++ b/debian/control @@ -1,8 +1,7 @@ Source: aiodns Section: python Priority: optional -Maintainer: Debian Python Team -Uploaders: Scott Kitterman , Tanguy Ortolo +Maintainer: Debian QA Group Build-Depends: debhelper-compat (= 13), dh-python, @@ -11,8 +10,8 @@ Build-Depends: python3-setuptools, Standards-Version: 4.6.2 Homepage: https://github.com/saghul/aiodns -Vcs-Git: https://salsa.debian.org/python-team/packages/aiodns.git -Vcs-Browser: https://salsa.debian.org/python-team/packages/aiodns +Vcs-Git: https://salsa.debian.org/debian/packages/aiodns.git +Vcs-Browser: https://salsa.debian.org/debian/packages/aiodns Rules-Requires-Root: no Package: python3-aiodns diff --git a/debian/patches/0002-Skip-bad-test.patch b/debian/patches/0002-Skip-bad-test.patch deleted file mode 100644 index 9eb5f5b..0000000 --- a/debian/patches/0002-Skip-bad-test.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Scott Kitterman -Date: Mon, 13 Mar 2023 21:22:32 -0400 -Subject: Skip bad test - ---- - tests.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/tests.py b/tests.py -index fc0e2b9..9b97b2f 100755 ---- a/tests.py -+++ b/tests.py -@@ -150,6 +150,8 @@ class DNSTest(unittest.TestCase): - with self.assertRaises(aiodns.error.DNSError): - self.loop.run_until_complete(f) - -+ # FIXME -+ @unittest.skip("The site used for this test no longer returns bad chars.") - def test_query_bad_chars(self): - f = self.resolver.query('xn--cardeosapeluqueros-r0b.com', 'MX') - result = self.loop.run_until_complete(f) diff --git a/debian/patches/python-3.10 b/debian/patches/python-3.10 deleted file mode 100644 index 1fa07cc..0000000 --- a/debian/patches/python-3.10 +++ /dev/null @@ -1,25 +0,0 @@ -From: =?utf-8?b?TWljaGHFgiBHw7Nybnk=?= -Date: Sat, 15 May 2021 10:03:01 +0200 -Subject: Remove loop= param from asyncio.sleep() to fix tests on Python 3.10 - -Fixes #95 - -Bug-Upstream: https://github.com/saghul/aiodns/issues/95 -Origin: upstream, https://github.com/saghul/aiodns/pull/96 ---- - tests.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests.py b/tests.py -index 7b2279f..fc0e2b9 100755 ---- a/tests.py -+++ b/tests.py -@@ -116,7 +116,7 @@ class DNSTest(unittest.TestCase): - f = self.resolver.query('google.com', 'A') - f.cancel() - async def coro(): -- await asyncio.sleep(0.1, loop=self.loop) -+ await asyncio.sleep(0.1) - await f - try: - self.loop.run_until_complete(coro()) diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index bdda1d5..0000000 --- a/debian/patches/series +++ /dev/null @@ -1,2 +0,0 @@ -python-3.10 -0002-Skip-bad-test.patch diff --git a/debian/watch b/debian/watch index 36fd204..30fbdcf 100644 --- a/debian/watch +++ b/debian/watch @@ -1,8 +1,3 @@ -# See uscan(1) for format - -# Compulsory line, this is a version 4 file version=4 -opts=uversionmangle=s/b/~b/ \ -https://github.com/saghul/@PACKAGE@/tags \ - .*/@PACKAGE@-@ANY_VERSION@@ARCHIVE_EXT@ \ - debian +opts=uversionmangle=s/(rc|a|b|c)/~$1/ \ +https://pypi.debian.net/@PACKAGE@/@PACKAGE@-(.+)\.tar\.gz diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 976ba02..0000000 --- a/mypy.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mypy] -ignore_missing_imports = True diff --git a/mypy_run.py b/mypy_run.py deleted file mode 100644 index 93053d8..0000000 --- a/mypy_run.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python - -from subprocess import run -import sys - -# Check if we're not cpython - Exit cleanly if so -if sys.implementation.name != "cpython": - sys.exit(0) - -# We only want to install if we're cpython too -install_success = run("pip install mypy", shell=True).returncode -if install_success: - print("mypy install failed", file=sys.stderr) - sys.exit(install_success) - -sys.exit(run("mypy aiodns", shell=True).returncode) diff --git a/setup.cfg b/setup.cfg index af57bc0..cfb9447 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1 +1,6 @@ [bdist_wheel] + +[egg_info] +tag_build = +tag_date = 0 + diff --git a/setup.py b/setup.py index 7cdb4f6..01d73f2 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,7 @@ def get_version(): long_description_content_type = "text/x-rst", install_requires = ['pycares>=4.0.0'], packages = ['aiodns'], + package_data = {"aiodns": ["py.typed"]}, platforms = ["POSIX", "Microsoft Windows"], classifiers = [ "Development Status :: 5 - Production/Stable", @@ -31,9 +32,10 @@ def get_version(): "Operating System :: Microsoft :: Windows", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9" + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" ] ) diff --git a/tests.py b/tests.py index 7b2279f..06f45f1 100755 --- a/tests.py +++ b/tests.py @@ -5,12 +5,25 @@ import unittest import socket import sys +import time import aiodns +try: + if sys.platform == "win32": + import winloop as uvloop + skip_uvloop = False + else: + import uvloop + skip_uvloop = False +except ModuleNotFoundError: + skip_uvloop = True + class DNSTest(unittest.TestCase): def setUp(self): + if sys.platform == 'win32': + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) self.loop = asyncio.new_event_loop() self.addCleanup(self.loop.close) self.resolver = aiodns.DNSResolver(loop=self.loop, timeout=5.0) @@ -77,7 +90,7 @@ def test_query_naptr(self): self.assertTrue(result) def test_query_ptr(self): - ip = '8.8.8.8' + ip = '172.253.122.26' f = self.resolver.query(ipaddress.ip_address(ip).reverse_pointer, 'PTR') result = self.loop.run_until_complete(f) self.assertTrue(result) @@ -96,13 +109,16 @@ def test_query_bad_class(self): self.assertRaises(ValueError, self.resolver.query, 'google.com', 'A', "INVALIDCLASS") def test_query_timeout(self): - self.resolver = aiodns.DNSResolver(timeout=0.1, loop=self.loop) + self.resolver = aiodns.DNSResolver(timeout=0.1, tries=1, loop=self.loop) self.resolver.nameservers = ['1.2.3.4'] f = self.resolver.query('google.com', 'A') + started = time.monotonic() try: self.loop.run_until_complete(f) except aiodns.error.DNSError as e: self.assertEqual(e.args[0], aiodns.error.ARES_ETIMEOUT) + # Ensure timeout really cuts time deadline. Limit duration to one second + self.assertLess(time.monotonic() - started, 1) def test_query_cancel(self): f = self.resolver.query('google.com', 'A') @@ -116,7 +132,7 @@ def test_future_cancel(self): f = self.resolver.query('google.com', 'A') f.cancel() async def coro(): - await asyncio.sleep(0.1, loop=self.loop) + await asyncio.sleep(0.1) await f try: self.loop.run_until_complete(coro()) @@ -135,6 +151,37 @@ def test_gethostbyname(self): result = self.loop.run_until_complete(f) self.assertTrue(result) + def test_getaddrinfo_address_family_0(self): + f = self.resolver.getaddrinfo('google.com') + result = self.loop.run_until_complete(f) + self.assertTrue(result) + self.assertTrue(len(result.nodes) > 1) + + def test_getaddrinfo_address_family_af_inet(self): + f = self.resolver.getaddrinfo('google.com', socket.AF_INET) + result = self.loop.run_until_complete(f) + self.assertTrue(result) + self.assertTrue(all(node.family == socket.AF_INET for node in result.nodes)) + + def test_getaddrinfo_address_family_af_inet6(self): + f = self.resolver.getaddrinfo('google.com', socket.AF_INET6) + result = self.loop.run_until_complete(f) + self.assertTrue(result) + self.assertTrue(all(node.family == socket.AF_INET6 for node in result.nodes)) + + def test_getnameinfo_ipv4(self): + f = self.resolver.getnameinfo(('127.0.0.1', 0)) + result = self.loop.run_until_complete(f) + self.assertTrue(result) + self.assertTrue(result.node) + + def test_getnameinfo_ipv6(self): + f = self.resolver.getnameinfo(('::1', 0, 0, 0)) + result = self.loop.run_until_complete(f) + self.assertTrue(result) + self.assertTrue(result.node) + + @unittest.skipIf(sys.platform == 'win32', 'skipped on Windows') def test_gethostbyaddr(self): f = self.resolver.gethostbyaddr('127.0.0.1') result = self.loop.run_until_complete(f) @@ -150,11 +197,19 @@ def test_gethostbyname_bad_family(self): with self.assertRaises(aiodns.error.DNSError): self.loop.run_until_complete(f) - def test_query_bad_chars(self): - f = self.resolver.query('xn--cardeosapeluqueros-r0b.com', 'MX') - result = self.loop.run_until_complete(f) - self.assertTrue(result) +# def test_query_bad_chars(self): +# f = self.resolver.query('xn--cardeosapeluqueros-r0b.com', 'MX') +# result = self.loop.run_until_complete(f) +# self.assertTrue(result) +@unittest.skipIf(skip_uvloop, "We don't have a uvloop or winloop module") +class TestUV_DNS(DNSTest): + def setUp(self): + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + self.loop = asyncio.new_event_loop() + self.addCleanup(self.loop.close) + self.resolver = aiodns.DNSResolver(loop=self.loop, timeout=5.0) + self.resolver.nameservers = ['8.8.8.8'] if __name__ == '__main__': unittest.main(verbosity=2)