From: Janus Date: Mon, 23 Jul 2018 14:11:00 +0000 (+0200) Subject: Initial type signatures X-Git-Tag: v1.16.0~13^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5c5de7bb1ad26d6d6bb82ed2deb64748b46ac599;p=thirdparty%2Fdnspython.git Initial type signatures --- diff --git a/.travis.yml b/.travis.yml index 85ef672b..ab0746e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,8 @@ branches: except: - python3 install: - - pip install unittest2 pylint pycryptodome ecdsa idna + - pip install typing pylint pycryptodome ecdsa idna script: + - make typecheck - make lint - make test diff --git a/Makefile b/Makefile index ca37045a..ce3e7161 100644 --- a/Makefile +++ b/Makefile @@ -70,3 +70,6 @@ lint: lint3: pylint3 dns tests examples/*.py + +typecheck: + if [ $(shell python -c "import sys; print(sys.version_info[0])") -ne 2 ]; then pip install mypy; mypy examples tests; else echo Skipping typecheck on Python 2; fi diff --git a/dns/dnssec.py b/dns/dnssec.py index f501cdaa..1bd422e3 100644 --- a/dns/dnssec.py +++ b/dns/dnssec.py @@ -278,7 +278,7 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): *rrset* is the RRset to validate. It can be a ``dns.rrset.RRset`` or a ``(dns.name.Name, dns.rdataset.Rdataset)`` tuple. - *rrsig* is a ``dns.rrset.Rdata``, the signature to validate. + *rrsig* is a ``dns.rdata.Rdata``, the signature to validate. *keys* is the key dictionary, used to find the DNSKEY associated with a given name. The dictionary is keyed by a ``dns.name.Name``, and has diff --git a/dns/dnssec.pyi b/dns/dnssec.pyi new file mode 100644 index 00000000..5699b3e1 --- /dev/null +++ b/dns/dnssec.pyi @@ -0,0 +1,19 @@ +from typing import Union, Dict, Tuple, Optional +from . import rdataset, rrset, exception, name, rdtypes, rdata, node +import dns.rdtypes.ANY.DS as DS +import dns.rdtypes.ANY.DNSKEY as DNSKEY + +_have_ecdsa : bool +_have_pycrypto : bool + +def validate_rrsig(rrset : Union[Tuple[name.Name, rdataset.Rdataset], rrset.RRset], rrsig : rdata.Rdata, keys : Dict[name.Name, Union[node.Node, rdataset.Rdataset]], origin : Optional[name.Name] = None, now : Optional[int] = None) -> None: + ... + +def validate(rrset: Union[Tuple[name.Name, rdataset.Rdataset], rrset.RRset], rrsigset : Union[Tuple[name.Name, rdataset.Rdataset], rrset.RRset], keys : Dict[name.Name, Union[node.Node, rdataset.Rdataset]], origin=None, now=None) -> None: + ... + +class ValidationFailure(exception.DNSException): + ... + +def make_ds(name : name.Name, key : DNSKEY.DNSKEY, algorithm : str, origin : Optional[name.Name] = None) -> DS.DS: + ... diff --git a/dns/e164.pyi b/dns/e164.pyi new file mode 100644 index 00000000..37a99fed --- /dev/null +++ b/dns/e164.pyi @@ -0,0 +1,10 @@ +from typing import Optional, Iterable +from . import name, resolver +def from_e164(text : str, origin=name.Name(".")) -> name.Name: + ... + +def to_e164(name : name.Name, origin : Optional[name.Name] = None, want_plus_prefix=True) -> str: + ... + +def query(number : str, domains : Iterable[str], resolver : Optional[resolver.Resolver] = None) -> resolver.Answer: + ... diff --git a/dns/entropy.pyi b/dns/entropy.pyi new file mode 100644 index 00000000..818f805a --- /dev/null +++ b/dns/entropy.pyi @@ -0,0 +1,10 @@ +from typing import Optional +from random import SystemRandom + +system_random : Optional[SystemRandom] + +def random_16() -> int: + pass + +def between(first: int, last: int) -> int: + pass diff --git a/dns/exception.pyi b/dns/exception.pyi new file mode 100644 index 00000000..4b346cc4 --- /dev/null +++ b/dns/exception.pyi @@ -0,0 +1,9 @@ +from typing import Set, Optional, Dict + +class DNSException(Exception): + supp_kwargs : Set[str] + kwargs : Optional[Dict] + +class SyntaxError(DNSException): ... +class FormError(DNSException): ... +class Timeout(DNSException): ... diff --git a/dns/inet.pyi b/dns/inet.pyi new file mode 100644 index 00000000..6d9dcc70 --- /dev/null +++ b/dns/inet.pyi @@ -0,0 +1,4 @@ +from typing import Union +from socket import AddressFamily + +AF_INET6 : Union[int, AddressFamily] diff --git a/dns/message.pyi b/dns/message.pyi new file mode 100644 index 00000000..ed99b3c0 --- /dev/null +++ b/dns/message.pyi @@ -0,0 +1,55 @@ +from typing import Optional, Dict, List, Tuple, Union +from . import name, rrset, tsig, rdatatype, entropy, edns, rdataclass +import hmac + +class Message: + def to_wire(self, origin : Optional[name.Name]=None, max_size=0, **kw) -> bytes: + ... + def find_rrset(self, section : List[rrset.RRset], name : name.Name, rdclass : int, rdtype : int, + covers=rdatatype.NONE, deleting : Optional[int]=None, create=False, + force_unique=False) -> rrset.RRset: + ... + def __init__(self, id : Optional[int] =None) -> None: + self.id : int + self.flags = 0 + self.question : List[rrset.RRset] = [] + self.answer : List[rrset.RRset] = [] + self.authority : List[rrset.RRset] = [] + self.additional : List[rrset.RRset] = [] + self.edns = -1 + self.ednsflags = 0 + self.payload = 0 + self.options : List[edns.Option] = [] + self.request_payload = 0 + self.keyring = None + self.keyname = None + self.keyalgorithm = tsig.default_algorithm + self.request_mac = b'' + self.other_data = b'' + self.tsig_error = 0 + self.fudge = 300 + self.original_id = self.id + self.mac = b'' + self.xfr = False + self.origin = None + self.tsig_ctx = None + self.had_tsig = False + self.multi = False + self.first = True + self.index : Dict[Tuple[rrset.RRset, name.Name, int, int, Union[int,str], int], rrset.RRset] = {} +def from_text(a : str) -> Message: + ... + +def from_wire(wire, keyring : Optional[Dict[name.Name,bytes]] = None, request_mac = b'', xfr=False, origin=None, + tsig_ctx : Optional[hmac.HMAC] = None, multi=False, first=True, + question_only=False, one_rr_per_rrset=False, + ignore_trailing=False) -> Message: + ... +def make_response(query : Message, recursion_available=False, our_payload=8192, + fudge=300) -> Message: + ... + +def make_query(qname : Union[name.Name,str], rdtype : Union[str,int], rdclass : Union[int,str] =rdataclass.IN, use_edns : Optional[bool] = None, + want_dnssec=False, ednsflags : Optional[int] = None, payload : Optional[int] = None, + request_payload : Optional[int] = None, options : Optional[List[edns.Option]] = None) -> Message: + ... diff --git a/dns/name.pyi b/dns/name.pyi new file mode 100644 index 00000000..5a8061b2 --- /dev/null +++ b/dns/name.pyi @@ -0,0 +1,35 @@ +from typing import Optional, Union, Tuple, Iterable, List + +class Name: + def is_subdomain(self, o : Name) -> bool: ... + def is_superdomain(self, o : Name) -> bool: ... + def __init__(self, labels : Iterable[Union[bytes,str]]) -> None: + self.labels : List[bytes] + def is_absolute(self) -> bool: ... + def is_wild(self) -> bool: ... + def fullcompare(self, other) -> Tuple[int,int,int]: ... + def canonicalize(self) -> Name: ... + def __lt__(self, other : Name): ... + def __le__(self, other : Name): ... + def __ge__(self, other : Name): ... + def __gt__(self, other : Name): ... + def to_text(self, omit_final_dot=False) -> str: ... + def to_unicode(self, omit_final_dot=False, idna_codec=None) -> str: ... + def to_digestable(self, origin=None) -> bytes: ... + def to_wire(self, file=None, compress=None, origin=None) -> Optional[bytes]: ... + def __add__(self, other : Name): ... + def __sub__(self, other : Name): ... + def split(self, depth) -> List[Tuple[str,str]]: ... + def concatenate(self, other : Name) -> Name: ... + def relativize(self, origin): ... + def derelativize(self, origin): ... + def choose_relativity(self, origin : Optional[Name] = None, relativize=True): ... + def parent(self) -> Name: ... + +class IDNACodec: + pass + +def from_text(text, origin : Optional[Name] = Name('.'), idna_codec : Optional[IDNACodec] = None) -> Name: + ... + +empty : Name diff --git a/dns/node.py b/dns/node.py index cc507b50..ad8dacb5 100644 --- a/dns/node.py +++ b/dns/node.py @@ -38,7 +38,7 @@ class Node(object): Each rdataset at the node is printed. Any keyword arguments to this method are passed on to the rdataset's to_text() method. - *name*, a ``dns.name.Name``, the owner name of the rdatasets. + *name*, a ``dns.name.Name`` or ``text``, the owner name of the rdatasets. Returns a ``text``. """ diff --git a/dns/node.pyi b/dns/node.pyi new file mode 100644 index 00000000..0997edf9 --- /dev/null +++ b/dns/node.pyi @@ -0,0 +1,17 @@ +from typing import List, Optional, Union +from . import rdataset, rdatatype, name +class Node: + def __init__(self): + self.rdatasets : List[rdataset.Rdataset] + def to_text(self, name : Union[str,name.Name], **kw) -> str: + ... + def find_rdataset(self, rdclass : int, rdtype : int, covers=rdatatype.NONE, + create=False) -> rdataset.Rdataset: + ... + def get_rdataset(self, rdclass : int, rdtype : int, covers=rdatatype.NONE, + create=False) -> Optional[rdataset.Rdataset]: + ... + def delete_rdataset(self, rdclass : int, rdtype : int, covers=rdatatype.NONE): + ... + def replace_rdataset(self, replacement : rdataset.Rdataset) -> None: + ... diff --git a/dns/query.py b/dns/query.py index 86654a57..71989333 100644 --- a/dns/query.py +++ b/dns/query.py @@ -273,7 +273,7 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, ignore_unexpected=False, one_rr_per_rrset=False, ignore_trailing=False): """Return the response obtained after sending a query via UDP. - *q*, a ``dns.message.message``, the query to send + *q*, a ``dns.message.Message``, the query to send *where*, a ``text`` containing an IPv4 or IPv6 address, where to send the message. @@ -441,7 +441,7 @@ def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, one_rr_per_rrset=False, ignore_trailing=False): """Return the response obtained after sending a query via TCP. - *q*, a ``dns.message.message``, the query to send + *q*, a ``dns.message.Message``, the query to send *where*, a ``text`` containing an IPv4 or IPv6 address, where to send the message. diff --git a/dns/query.pyi b/dns/query.pyi new file mode 100644 index 00000000..fe5ef826 --- /dev/null +++ b/dns/query.pyi @@ -0,0 +1,15 @@ +from typing import Optional, Union, Dict, Generator, Any +from . import message, tsig, rdatatype, rdataclass, name, message +def tcp(q : message.Message, where : str, timeout : float = None, port=53, af : Optional[int] = None, source : Optional[str] = None, source_port : int = 0, + one_rr_per_rrset=False) -> message.Message: + pass + +def xfr(where : None, zone : Union[name.Name,str], rdtype=rdatatype.AXFR, rdclass=rdataclass.IN, + timeout : Optional[float] =None, port=53, keyring : Optional[Dict[name.Name, bytes]] =None, keyname : Union[str,name.Name]=None, relativize=True, + af : Optional[int] =None, lifetime : Optional[float]=None, source : Optional[str] =None, source_port=0, serial=0, + use_udp=False, keyalgorithm=tsig.default_algorithm) -> Generator[Any,Any,message.Message]: + pass + +def udp(q : message.Message, where : str, timeout : Optional[float] = None, port=53, af : Optional[int] = None, source : Optional[str] = None, source_port=0, + ignore_unexpected=False, one_rr_per_rrset=False) -> message.Message: + ... diff --git a/dns/rdata.pyi b/dns/rdata.pyi new file mode 100644 index 00000000..8663955c --- /dev/null +++ b/dns/rdata.pyi @@ -0,0 +1,17 @@ +from typing import Dict, Tuple, Any, Optional +from .name import Name +class Rdata: + def __init__(self): + self.address : str + def to_wire(self, file, compress : Optional[Dict[Name,int]], origin : Optional[Name]) -> bytes: + ... + @classmethod + def from_text(cls, rdclass : int, rdtype : int, tok, origin=None, relativize=True): + ... +_rdata_modules : Dict[Tuple[Any,Rdata],Any] + +def from_text(rdclass : int, rdtype : int, tok : Optional[str], origin : Optional[Name] = None, relativize : bool = True): + ... + +def from_wire(rdclass : int, rdtype : int, wire : bytes, current : int, rdlen : int, origin : Optional[Name] = None): + ... diff --git a/dns/rdataset.pyi b/dns/rdataset.pyi new file mode 100644 index 00000000..3efff88a --- /dev/null +++ b/dns/rdataset.pyi @@ -0,0 +1,58 @@ +from typing import Optional, Dict, List, Union +from io import BytesIO +from . import exception, name, set, rdatatype, rdata, rdataset + +class DifferingCovers(exception.DNSException): + """An attempt was made to add a DNS SIG/RRSIG whose covered type + is not the same as that of the other rdatas in the rdataset.""" + + +class IncompatibleTypes(exception.DNSException): + """An attempt was made to add DNS RR data of an incompatible type.""" + + +class Rdataset(set.Set): + def __init__(self, rdclass, rdtype, covers=rdatatype.NONE, ttl=0): + self.rdclass : int = rdclass + self.rdtype : int = rdtype + self.covers : int = covers + self.ttl : int = ttl + + def update_ttl(self, ttl : int) -> None: + ... + + def add(self, rd : rdata.Rdata, ttl : Optional[int] =None): + ... + + def union_update(self, other : Rdataset): + ... + + def intersection_update(self, other : Rdataset): + ... + + def update(self, other : Rdataset): + ... + + def to_text(self, name : Optional[name.Name] =None, origin : Optional[name.Name] =None, relativize=True, + override_rdclass : Optional[int] =None, **kw) -> bytes: + ... + + def to_wire(self, name : Optional[name.Name], file : BytesIO, compress : Optional[Dict[name.Name, int]] = None, origin : Optional[name.Name] = None, + override_rdclass : Optional[int] = None, want_shuffle=True) -> int: + ... + + def match(self, rdclass : int, rdtype : int, covers : int) -> bool: + ... + + +def from_text_list(rdclass : Union[int,str], rdtype : Union[int,str], ttl : int, text_rdatas : str) -> rdataset.Rdataset: + ... + +def from_text(rdclass : Union[int,str], rdtype : Union[int,str], ttl : int, *text_rdatas : str) -> rdataset.Rdataset: + ... + +def from_rdata_list(ttl : int, rdatas : List[rdata.Rdata]) -> rdataset.Rdataset: + ... + +def from_rdata(ttl : int, *rdatas : List[rdata.Rdata]) -> rdataset.Rdataset: + ... diff --git a/dns/rdtypes/dnskeybase.pyi b/dns/rdtypes/dnskeybase.pyi new file mode 100644 index 00000000..e102a698 --- /dev/null +++ b/dns/rdtypes/dnskeybase.pyi @@ -0,0 +1,37 @@ +from typing import Set, Any + +SEP : int +REVOKE : int +ZONE : int + +def flags_to_text_set(flags : int) -> Set[str]: + ... + +def flags_from_text_set(texts_set) -> int: + ... + +from .. import rdata + +class DNSKEYBase(rdata.Rdata): + def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): + self.flags : int + self.protocol : int + self.key : str + self.algorithm : int + + def to_text(self, origin : Any = None, relativize=True, **kw : Any): + ... + + @classmethod + def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): + ... + + def to_wire(self, file, compress=None, origin=None): + ... + + @classmethod + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): + ... + + def flags_to_text_set(self) -> Set[str]: + ... diff --git a/dns/rdtypes/txtbase.pyi b/dns/rdtypes/txtbase.pyi new file mode 100644 index 00000000..af447d50 --- /dev/null +++ b/dns/rdtypes/txtbase.pyi @@ -0,0 +1,6 @@ +from .. import rdata + +class TXTBase(rdata.Rdata): + ... +class TXT(TXTBase): + ... diff --git a/dns/resolver.pyi b/dns/resolver.pyi new file mode 100644 index 00000000..e839ec21 --- /dev/null +++ b/dns/resolver.pyi @@ -0,0 +1,31 @@ +from typing import Union, Optional, List +from . import exception, rdataclass, name, rdatatype + +import socket +_gethostbyname = socket.gethostbyname +class NXDOMAIN(exception.DNSException): + ... +def query(qname : str, rdtype : Union[int,str] = 0, rdclass : Union[int,str] = 0, + tcp=False, source=None, raise_on_no_answer=True, + source_port=0): + ... +class LRUCache: + def __init__(self, max_size=1000): + ... + def get(self, key): + ... + def put(self, key, val): + ... +class Answer: + def __init__(self, qname, rdtype, rdclass, response, + raise_on_no_answer=True): + ... +def zone_for_name(name, rdclass : int = rdataclass.IN, tcp=False, resolver : Optional[Resolver] = None): + ... + +class Resolver: + def __init__(self, configure): + self.nameservers : List[str] + def query(self, qname : str, rdtype : Union[int,str] = rdatatype.A, rdclass : Union[int,str] = rdataclass.IN, + tcp : bool = False, source : Optional[str] = None, raise_on_no_answer=True, source_port : int = 0): + ... diff --git a/dns/reversename.pyi b/dns/reversename.pyi new file mode 100644 index 00000000..97f072ea --- /dev/null +++ b/dns/reversename.pyi @@ -0,0 +1,6 @@ +from . import name +def from_address(text : str) -> name.Name: + ... + +def to_address(name : name.Name) -> str: + ... diff --git a/dns/rrset.pyi b/dns/rrset.pyi new file mode 100644 index 00000000..0a81a2a0 --- /dev/null +++ b/dns/rrset.pyi @@ -0,0 +1,10 @@ +from typing import List, Optional +from . import rdataset, rdatatype + +class RRset(rdataset.Rdataset): + def __init__(self, name, rdclass : int , rdtype : int, covers=rdatatype.NONE, + deleting : Optional[int] =None) -> None: + self.name = name + self.deleting = deleting +def from_text(name : str, ttl : int, rdclass : str, rdtype : str, *text_rdatas : str): + ... diff --git a/dns/tsigkeyring.pyi b/dns/tsigkeyring.pyi new file mode 100644 index 00000000..b5d51e15 --- /dev/null +++ b/dns/tsigkeyring.pyi @@ -0,0 +1,7 @@ +from typing import Dict +from . import name + +def from_text(textring : Dict[str,str]) -> Dict[name.Name,bytes]: + ... +def to_text(keyring : Dict[name.Name,bytes]) -> Dict[str, str]: + ... diff --git a/dns/update.pyi b/dns/update.pyi new file mode 100644 index 00000000..eeac0591 --- /dev/null +++ b/dns/update.pyi @@ -0,0 +1,21 @@ +from typing import Optional,Dict,Union,Any + +from . import message, tsig, rdataclass, name + +class Update(message.Message): + def __init__(self, zone : Union[name.Name, str], rdclass : Union[int,str] = rdataclass.IN, keyring : Optional[Dict[name.Name,bytes]] = None, + keyname : Optional[name.Name] = None, keyalgorithm : Optional[name.Name] = tsig.default_algorithm) -> None: + self.id : int + def add(self, name : Union[str,name.Name], *args : Any): + ... + def delete(self, name, *args : Any): + ... + def replace(self, name : Union[str,name.Name], *args : Any): + ... + def present(self, name : Union[str,name.Name], *args : Any): + ... + def absent(self, name : Union[str,name.Name], rdtype=None): + """Require that an owner name (and optionally an rdata type) does + not exist as a prerequisite to the execution of the update.""" + def to_wire(self, origin : Optional[name.Name] = None, max_size=65535, **kw) -> bytes: + ... diff --git a/dns/zone.py b/dns/zone.py index d5082de4..2c7ea693 100644 --- a/dns/zone.py +++ b/dns/zone.py @@ -259,7 +259,7 @@ class Zone(object): exist? @type create: bool @raises KeyError: the node or rdata could not be found - @rtype: dns.rrset.RRset object + @rtype: dns.rdataset.Rdataset object """ name = self._validate_name(name) @@ -294,7 +294,7 @@ class Zone(object): @param create: should the node and rdataset be created if they do not exist? @type create: bool - @rtype: dns.rrset.RRset object + @rtype: dns.rdataset.Rdataset object or None """ try: diff --git a/dns/zone.pyi b/dns/zone.pyi new file mode 100644 index 00000000..911d7a01 --- /dev/null +++ b/dns/zone.pyi @@ -0,0 +1,55 @@ +from typing import Generator, Optional, Union, Tuple, Iterable, Callable, Any, Iterator, TextIO, BinaryIO, Dict +from . import rdata, zone, rdataclass, name, rdataclass, message, rdatatype, exception, node, rdataset, rrset, rdatatype + +class BadZone(exception.DNSException): ... +class NoSOA(BadZone): ... +class NoNS(BadZone): ... +class UnknownOrigin(BadZone): ... + +class Zone: + def __getitem__(self, key : str) -> node.Node: + ... + def __init__(self, origin : Union[str,name.Name], rdclass : int = rdataclass.IN, relativize : bool = True) -> None: + self.nodes : Dict[str,node.Node] + self.origin = origin + def values(self): + return self.nodes.values() + def iterate_rdatas(self, rdtype : Union[int,str] = rdatatype.ANY, covers : Union[int,str] = None) -> Iterable[Tuple[name.Name, int, rdata.Rdata]]: + ... + def __iter__(self) -> Iterator[str]: + ... + def get_node(self, name : Union[name.Name,str], create=False) -> Optional[node.Node]: + ... + def find_rrset(self, name : Union[str,name.Name], rdtype : Union[int,str], covers=rdatatype.NONE) -> rrset.RRset: + ... + def find_rdataset(self, name : Union[str,name.Name], rdtype : Union[str,int], covers=rdatatype.NONE, + create=False) -> rdataset.Rdataset: + ... + def get_rdataset(self, name : Union[str,name.Name], rdtype : Union[str,int], covers=rdatatype.NONE, create=False) -> Optional[rdataset.Rdataset]: + ... + def get_rrset(self, name : Union[str,name.Name], rdtype : Union[str,int], covers=rdatatype.NONE) -> Optional[rrset.RRset]: + ... + def replace_rdataset(self, name : Union[str,name.Name], replacement : rdataset.Rdataset) -> None: + ... + def delete_rdataset(self, name : Union[str,name.Name], rdtype : Union[str,int], covers=rdatatype.NONE) -> None: + ... + def iterate_rdatasets(self, rdtype : Union[str,int] =rdatatype.ANY, + covers : Union[str,int] =rdatatype.NONE): + ... + def to_file(self, f : Union[TextIO, BinaryIO, str], sorted=True, relativize=True, nl : Optional[bytes] = None): + ... + def to_text(self, sorted=True, relativize=True, nl : Optional[bytes] = None) -> bytes: + ... + +def from_xfr(xfr : Generator[Any,Any,message.Message], zone_factory : Callable[..., zone.Zone] = zone.Zone, relativize=True, check_origin=True): + ... + +def from_text(text : str, origin : Optional[Union[str,name.Name]] = None, rdclass : int = rdataclass.IN, + relativize=True, zone_factory : Callable[...,zone.Zone] = zone.Zone, filename : Optional[str] = None, + allow_include=False, check_origin=True) -> zone.Zone: + ... + +def from_file(f, origin : Optional[Union[str,name.Name]] = None, rdclass=rdataclass.IN, + relativize=True, zone_factory : Callable[..., zone.Zone] = Zone, filename : Optional[str] = None, + allow_include=True, check_origin=True) -> zone.Zone: + ... diff --git a/examples/receive_notify.py b/examples/receive_notify.py index 93c428c4..178d73cb 100644 --- a/examples/receive_notify.py +++ b/examples/receive_notify.py @@ -11,6 +11,9 @@ import dns.flags import dns.message import dns.rdataclass import dns.rdatatype +import dns.name + +from typing import cast address = '127.0.0.1' port = 53535 @@ -26,7 +29,7 @@ while True: # Do something with the SOA RR here print('The serial number for', soa.name, 'is', soa[0].serial) - response = dns.message.make_response(notify) + response = dns.message.make_response(notify) # type: dns.message.Message response.flags |= dns.flags.AA - wire = response.to_wire(response) + wire = response.to_wire(cast(dns.name.Name, response)) s.sendto(wire, address) diff --git a/examples/reverse.py b/examples/reverse.py index b84017fd..038a0201 100755 --- a/examples/reverse.py +++ b/examples/reverse.py @@ -22,13 +22,15 @@ import dns.zone import dns.ipv4 import os.path import sys +from typing import Dict, List # pylint: disable=unused-import -reverse_map = {} +reverse_map = {} # type: Dict[str, List[str]] for filename in sys.argv[1:]: zone = dns.zone.from_file(filename, os.path.basename(filename), relativize=False) for (name, ttl, rdata) in zone.iterate_rdatas('A'): + print(type(rdata)) try: reverse_map[rdata.address].append(name.to_text()) except KeyError: diff --git a/examples/zonediff.py b/examples/zonediff.py index b05d7a46..bfe4ee3d 100755 --- a/examples/zonediff.py +++ b/examples/zonediff.py @@ -22,16 +22,22 @@ """See diff_zones.__doc__ for more information""" from __future__ import print_function +from typing import cast, Union, Any # pylint: disable=unused-import __all__ = ['diff_zones', 'format_changes_plain', 'format_changes_html'] try: import dns.zone + import dns.node except ImportError: raise SystemExit("Please install dnspython") -def diff_zones(zone1, zone2, ignore_ttl=False, ignore_soa=False): +def diff_zones(zone1, # type: dns.zone.Zone + zone2, # type: dns.zone.Zone + ignore_ttl=False, + ignore_soa=False + ): # type: (...) -> list """diff_zones(zone1, zone2, ignore_ttl=False, ignore_soa=False) -> changes Compares two dns.zone.Zone objects and returns a list of all changes in the format (name, oldnode, newnode). @@ -47,22 +53,26 @@ def diff_zones(zone1, zone2, ignore_ttl=False, ignore_soa=False): changes = [] for name in zone1: - name = str(name) - n1 = zone1.get_node(name) - n2 = zone2.get_node(name) + namestr = str(name) + n1 = cast(dns.node.Node, zone1.get_node(namestr)) + n2 = cast(dns.node.Node, zone2.get_node(namestr)) if not n2: changes.append((str(name), n1, n2)) elif _nodes_differ(n1, n2, ignore_ttl, ignore_soa): changes.append((str(name), n1, n2)) for name in zone2: - n1 = zone1.get_node(name) - if not n1: - n2 = zone2.get_node(name) - changes.append((str(name), n1, n2)) + n3 = cast(dns.node.Node, zone1.get_node(name)) + if not n3: + n4 = cast(dns.node.Node, zone2.get_node(name)) + changes.append((str(name), n3, n4)) return changes -def _nodes_differ(n1, n2, ignore_ttl, ignore_soa): +def _nodes_differ(n1, # type: dns.node.Node + n2, # type: dns.node.Node + ignore_ttl, # type: bool + ignore_soa # type: bool + ): # type: (...) -> bool if ignore_soa or not ignore_ttl: # Compare datasets directly for r in n1.rdatasets: @@ -78,10 +88,15 @@ def _nodes_differ(n1, n2, ignore_ttl, ignore_soa): continue if r not in n1.rdatasets: return True + assert False else: return n1 != n2 -def format_changes_plain(oldf, newf, changes, ignore_ttl=False): +def format_changes_plain(oldf, # type: str + newf, # type: str + changes, # type: list + ignore_ttl=False + ): # type: (...) -> str """format_changes(oldfile, newfile, changes, ignore_ttl=False) -> str Given 2 filenames and a list of changes from diff_zones, produce diff-like output. If ignore_ttl is True, TTL-only changes are not displayed""" @@ -110,7 +125,11 @@ def format_changes_plain(oldf, newf, changes, ignore_ttl=False): ret += "+ %s\n" % str(r).replace('\n', '\n+ ') return ret -def format_changes_html(oldf, newf, changes, ignore_ttl=False): +def format_changes_html(oldf, # type: str + newf, # type: str + changes, # type: list + ignore_ttl=False + ): # type: (...) -> str """format_changes(oldfile, newfile, changes, ignore_ttl=False) -> str Given 2 filenames and a list of changes from diff_zones, produce nice html output. If ignore_ttl is True, TTL-only changes are not displayed""" @@ -161,7 +180,7 @@ def format_changes_html(oldf, newf, changes, ignore_ttl=False): # Make this module usable as a script too. -def main(): +def main(): # type: () -> None import argparse import subprocess import sys @@ -190,7 +209,7 @@ The differences shown will be logical differences, not textual differences. opts, args = p.parse_args() opts.use_vc = opts.use_git or opts.use_bzr or opts.use_rcs - def _open(what, err): + def _open(what, err): # type: (Union[list,str], str) -> Any if isinstance(what, list): # Must be a list, open subprocess try: @@ -265,7 +284,7 @@ The differences shown will be logical differences, not textual differences. try: oldz = dns.zone.from_file(old, origin='.', check_origin=False) except dns.exception.DNSException: - sys.stderr.write("Incorrect zonefile: %s\n", old) + sys.stderr.write("Incorrect zonefile: %s\n" % old) if opts.tracebacks: traceback.print_exc() try: diff --git a/tests/test_bugs.py b/tests/test_bugs.py index c153c543..8d509a5f 100644 --- a/tests/test_bugs.py +++ b/tests/test_bugs.py @@ -14,10 +14,7 @@ # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. from io import BytesIO -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import binascii diff --git a/tests/test_dnssec.py b/tests/test_dnssec.py index 78b1cdc9..bec6ede5 100644 --- a/tests/test_dnssec.py +++ b/tests/test_dnssec.py @@ -15,10 +15,7 @@ from __future__ import print_function -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.dnssec import dns.name @@ -156,74 +153,74 @@ abs_ecdsa384_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', "Pycryptodome cannot be imported") class DNSSECValidatorTestCase(unittest.TestCase): - def testAbsoluteRSAGood(self): + def testAbsoluteRSAGood(self): # type: () -> None dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when) - def testDuplicateKeytag(self): + def testDuplicateKeytag(self): # type: () -> None dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys_duplicate_keytag, None, when) - def testAbsoluteRSABad(self): - def bad(): + def testAbsoluteRSABad(self): # type: () -> None + def bad(): # type: () -> None dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None, when) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) - def testRelativeRSAGood(self): + def testRelativeRSAGood(self): # type: () -> None dns.dnssec.validate(rel_soa, rel_soa_rrsig, rel_keys, abs_dnspython_org, when) - def testRelativeRSABad(self): - def bad(): + def testRelativeRSABad(self): # type: () -> None + def bad(): # type: () -> None dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys, abs_dnspython_org, when) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) - def testMakeSHA256DS(self): + def testMakeSHA256DS(self): # type: () -> None ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256') self.failUnless(ds == good_ds) - def testAbsoluteDSAGood(self): + def testAbsoluteDSAGood(self): # type: () -> None dns.dnssec.validate(abs_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, when2) - def testAbsoluteDSABad(self): - def bad(): + def testAbsoluteDSABad(self): # type: () -> None + def bad(): # type: () -> None dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, when2) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) - def testMakeExampleSHA1DS(self): + def testMakeExampleSHA1DS(self): # type: () -> None ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA1') self.failUnless(ds == example_ds_sha1) - def testMakeExampleSHA256DS(self): + def testMakeExampleSHA256DS(self): # type: () -> None ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') self.failUnless(ds == example_ds_sha256) @unittest.skipUnless(dns.dnssec._have_ecdsa, "python ECDSA cannot be imported") - def testAbsoluteECDSA256Good(self): + def testAbsoluteECDSA256Good(self): # type: () -> None dns.dnssec.validate(abs_ecdsa256_soa, abs_ecdsa256_soa_rrsig, abs_ecdsa256_keys, None, when3) @unittest.skipUnless(dns.dnssec._have_ecdsa, "python ECDSA cannot be imported") - def testAbsoluteECDSA256Bad(self): - def bad(): + def testAbsoluteECDSA256Bad(self): # type: () -> None + def bad(): # type: () -> None dns.dnssec.validate(abs_other_ecdsa256_soa, abs_ecdsa256_soa_rrsig, abs_ecdsa256_keys, None, when3) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) @unittest.skipUnless(dns.dnssec._have_ecdsa, "python ECDSA cannot be imported") - def testAbsoluteECDSA384Good(self): + def testAbsoluteECDSA384Good(self): # type: () -> None dns.dnssec.validate(abs_ecdsa384_soa, abs_ecdsa384_soa_rrsig, abs_ecdsa384_keys, None, when4) @unittest.skipUnless(dns.dnssec._have_ecdsa, "python ECDSA cannot be imported") - def testAbsoluteECDSA384Bad(self): - def bad(): + def testAbsoluteECDSA384Bad(self): # type: () -> None + def bad(): # type: () -> None dns.dnssec.validate(abs_other_ecdsa384_soa, abs_ecdsa384_soa_rrsig, abs_ecdsa384_keys, None, when4) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) diff --git a/tests/test_edns.py b/tests/test_edns.py index f15a28a3..01dfdda8 100644 --- a/tests/test_edns.py +++ b/tests/test_edns.py @@ -16,10 +16,7 @@ from __future__ import print_function -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from io import BytesIO diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 4e071070..a684ca1f 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from dns.exception import DNSException diff --git a/tests/test_flags.py b/tests/test_flags.py index 9d230ac1..0a603ffa 100644 --- a/tests/test_flags.py +++ b/tests/test_flags.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.flags import dns.rcode diff --git a/tests/test_generate.py b/tests/test_generate.py index 1dd29cdd..607a5c1b 100644 --- a/tests/test_generate.py +++ b/tests/test_generate.py @@ -16,10 +16,7 @@ import sys sys.path.insert(0, '../') # Force the local project to be *the* dns -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.exception import dns.rdata @@ -140,17 +137,17 @@ def _rdata_sort(a): class GenerateTestCase(unittest.TestCase): - def testFromText(self): - def bad(): + def testFromText(self): # type: () -> None + def bad(): # type: () -> None dns.zone.from_text(example_text, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoSOA, bad) - def testFromText1(self): - def bad(): + def testFromText1(self): # type: () -> None + def bad(): # type: () -> None dns.zone.from_text(example_text1, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoSOA, bad) - def testIterateAllRdatas2(self): + def testIterateAllRdatas2(self): # type: () -> None z = dns.zone.from_text(example_text2, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) @@ -194,7 +191,7 @@ class GenerateTestCase(unittest.TestCase): exl.sort(key=_rdata_sort) self.failUnless(l == exl) - def testIterateAllRdatas3(self): + def testIterateAllRdatas3(self): # type: () -> None z = dns.zone.from_text(example_text3, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) @@ -233,7 +230,7 @@ class GenerateTestCase(unittest.TestCase): '10.0.0.8'))] exl.sort(key=_rdata_sort) self.failUnless(l == exl) - def testGenerate1(self): + def testGenerate1(self): # type: () -> None z = dns.zone.from_text(example_text4, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) @@ -279,7 +276,7 @@ class GenerateTestCase(unittest.TestCase): exl.sort(key=_rdata_sort) self.assertEqual(l, exl) - def testGenerate2(self): + def testGenerate2(self): # type: () -> None z = dns.zone.from_text(example_text5, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) @@ -322,7 +319,7 @@ class GenerateTestCase(unittest.TestCase): exl.sort(key=_rdata_sort) self.failUnless(l == exl) - def testGenerate3(self): + def testGenerate3(self): # type: () -> None z = dns.zone.from_text(example_text6, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) @@ -365,7 +362,7 @@ class GenerateTestCase(unittest.TestCase): exl.sort(key=_rdata_sort) self.failUnless(l == exl) - def testGenerate4(self): + def testGenerate4(self): # type: () -> None z = dns.zone.from_text(example_text7, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) @@ -408,7 +405,7 @@ class GenerateTestCase(unittest.TestCase): exl.sort(key=_rdata_sort) self.failUnless(l == exl) - def testGenerate6(self): + def testGenerate6(self): # type: () -> None z = dns.zone.from_text(example_text9, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) @@ -458,7 +455,7 @@ class GenerateTestCase(unittest.TestCase): exl.sort(key=_rdata_sort) self.failUnless(l == exl) - def testGenerate7(self): + def testGenerate7(self): # type: () -> None z = dns.zone.from_text(example_text10, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) diff --git a/tests/test_grange.py b/tests/test_grange.py index 567f8a34..73e065b4 100644 --- a/tests/test_grange.py +++ b/tests/test_grange.py @@ -16,10 +16,7 @@ import sys sys.path.insert(0, '../') -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns import dns.exception diff --git a/tests/test_message.py b/tests/test_message.py index fc4ad375..81738e81 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import binascii import dns.exception diff --git a/tests/test_name.py b/tests/test_name.py index 85007b3b..f3f04c3a 100644 --- a/tests/test_name.py +++ b/tests/test_name.py @@ -16,10 +16,8 @@ from __future__ import print_function -try: - import unittest2 as unittest -except ImportError: - import unittest +from typing import Dict # pylint: disable=unused-import +import unittest from io import BytesIO @@ -380,14 +378,14 @@ class NameTestCase(unittest.TestCase): def testToWire1(self): n = dns.name.from_text('FOO.bar') f = BytesIO() - compress = {} + compress = {} # type: Dict[dns.name.Name,int] n.to_wire(f, compress) self.assertEqual(f.getvalue(), b'\x03FOO\x03bar\x00') def testToWire2(self): n = dns.name.from_text('FOO.bar') f = BytesIO() - compress = {} + compress = {} # type: Dict[dns.name.Name,int] n.to_wire(f, compress) n.to_wire(f, compress) self.assertEqual(f.getvalue(), b'\x03FOO\x03bar\x00\xc0\x00') @@ -396,7 +394,7 @@ class NameTestCase(unittest.TestCase): n1 = dns.name.from_text('FOO.bar') n2 = dns.name.from_text('foo.bar') f = BytesIO() - compress = {} + compress = {} # type: Dict[dns.name.Name,int] n1.to_wire(f, compress) n2.to_wire(f, compress) self.assertEqual(f.getvalue(), b'\x03FOO\x03bar\x00\xc0\x00') @@ -405,7 +403,7 @@ class NameTestCase(unittest.TestCase): n1 = dns.name.from_text('FOO.bar') n2 = dns.name.from_text('a.foo.bar') f = BytesIO() - compress = {} + compress = {} # type: Dict[dns.name.Name,int] n1.to_wire(f, compress) n2.to_wire(f, compress) self.assertEqual(f.getvalue(), b'\x03FOO\x03bar\x00\x01\x61\xc0\x00') @@ -414,7 +412,7 @@ class NameTestCase(unittest.TestCase): n1 = dns.name.from_text('FOO.bar') n2 = dns.name.from_text('a.foo.bar') f = BytesIO() - compress = {} + compress = {} # type: Dict[dns.name.Name,int] n1.to_wire(f, compress) n2.to_wire(f, None) self.assertEqual(f.getvalue(), @@ -429,7 +427,7 @@ class NameTestCase(unittest.TestCase): def bad(): n = dns.name.from_text('FOO.bar', None) f = BytesIO() - compress = {} + compress = {} # type: Dict[dns.name.Name,int] n.to_wire(f, compress) self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) diff --git a/tests/test_namedict.py b/tests/test_namedict.py index 35f0b78e..6700aeca 100644 --- a/tests/test_namedict.py +++ b/tests/test_namedict.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.name import dns.namedict diff --git a/tests/test_nsec3.py b/tests/test_nsec3.py index 261c124a..9fd9e7fa 100644 --- a/tests/test_nsec3.py +++ b/tests/test_nsec3.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.rdata import dns.rdataclass diff --git a/tests/test_ntoaaton.py b/tests/test_ntoaaton.py index f51592b6..e3480491 100644 --- a/tests/test_ntoaaton.py +++ b/tests/test_ntoaaton.py @@ -15,10 +15,7 @@ from __future__ import print_function -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import binascii import dns.exception diff --git a/tests/test_rdata.py b/tests/test_rdata.py index f693ba0b..9eba49db 100644 --- a/tests/test_rdata.py +++ b/tests/test_rdata.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.rdata import dns.rdataclass diff --git a/tests/test_rdtypeandclass.py b/tests/test_rdtypeandclass.py index 1a1f0408..0f7bac25 100644 --- a/tests/test_rdtypeandclass.py +++ b/tests/test_rdtypeandclass.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.rdataclass import dns.rdatatype diff --git a/tests/test_rdtypeanydnskey.py b/tests/test_rdtypeanydnskey.py index c99cfe50..4fea7afc 100644 --- a/tests/test_rdtypeanydnskey.py +++ b/tests/test_rdtypeanydnskey.py @@ -14,20 +14,18 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.rrset import dns.rdtypes.ANY.DNSKEY +from typing import Set # pylint: disable=unused-import class RdtypeAnyDnskeyTestCase(unittest.TestCase): - def testFlagsEmpty(self): + def testFlagsEmpty(self): # type: () -> None '''Test DNSKEY flag to/from text conversion for zero flag/empty set.''' - good_s = set() + good_s = set() #type: Set[str] good_f = 0 from_flags = dns.rdtypes.ANY.DNSKEY.flags_to_text_set(good_f) self.failUnless(from_flags == good_s, @@ -36,7 +34,7 @@ class RdtypeAnyDnskeyTestCase(unittest.TestCase): self.failUnless(from_set == good_f, '"0x%x" != "0x%x"' % (from_set, good_f)) - def testFlagsAll(self): + def testFlagsAll(self): # type: () -> None '''Test that all defined flags are recognized.''' good_s = set(['SEP', 'REVOKE', 'ZONE']) good_f = 0x181 @@ -47,19 +45,19 @@ class RdtypeAnyDnskeyTestCase(unittest.TestCase): self.failUnless(from_text == good_f, '"0x%x" != "0x%x"' % (from_text, good_f)) - def testFlagsUnknownToText(self): + def testFlagsUnknownToText(self): # type: () -> None '''Test that undefined flags are returned in hexadecimal notation.''' unk_s = set(['0x8000']) flags_s = dns.rdtypes.ANY.DNSKEY.flags_to_text_set(0x8000) self.failUnless(flags_s == unk_s, '"%s" != "%s"' % (flags_s, unk_s)) - def testFlagsUnknownToFlags(self): + def testFlagsUnknownToFlags(self): # type: () -> None '''Test that conversion from undefined mnemonic raises error.''' self.failUnlessRaises(NotImplementedError, dns.rdtypes.ANY.DNSKEY.flags_from_text_set, (['0x8000'])) - def testFlagsRRToText(self): + def testFlagsRRToText(self): # type: () -> None '''Test that RR method returns correct flags.''' rr = dns.rrset.from_text('foo', 300, 'IN', 'DNSKEY', '257 3 8 KEY=')[0] rr_s = set(['ZONE', 'SEP']) diff --git a/tests/test_rdtypeanyeui.py b/tests/test_rdtypeanyeui.py index e9d03030..625c0c3c 100644 --- a/tests/test_rdtypeanyeui.py +++ b/tests/test_rdtypeanyeui.py @@ -14,10 +14,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from io import BytesIO import dns.rrset diff --git a/tests/test_rdtypeanyloc.py b/tests/test_rdtypeanyloc.py index 43fa4932..e6936c3d 100644 --- a/tests/test_rdtypeanyloc.py +++ b/tests/test_rdtypeanyloc.py @@ -14,10 +14,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.rrset import dns.rdtypes.ANY.LOC diff --git a/tests/test_resolver.py b/tests/test_resolver.py index 183d2a18..4bc368f6 100644 --- a/tests/test_resolver.py +++ b/tests/test_resolver.py @@ -18,10 +18,7 @@ import select import sys import socket import time -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.message import dns.name @@ -349,7 +346,7 @@ class NXDOMAINExceptionTestCase(unittest.TestCase): try: raise dns.resolver.NXDOMAIN(qnames=[n2, n1]) - except Exception as e: + except dns.resolver.NXDOMAIN as e: e0 = dns.resolver.NXDOMAIN("errmsg") e = e0 + e MSG = "None of DNS query names exist: a.b.s., a.b." @@ -371,7 +368,7 @@ class NXDOMAINExceptionTestCase(unittest.TestCase): try: raise dns.resolver.NXDOMAIN(qnames=[n1], responses={n1: 'r1.1'}) - except Exception as e: + except dns.resolver.NXDOMAIN as e: MSG = "The DNS query name does not exist: a.b." if not PY3: # pylint: disable=exception-message-attribute diff --git a/tests/test_rrset.py b/tests/test_rrset.py index 663a52eb..2bf4c099 100644 --- a/tests/test_rrset.py +++ b/tests/test_rrset.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.rrset diff --git a/tests/test_set.py b/tests/test_set.py index 4816aa9b..e85c5f6d 100644 --- a/tests/test_set.py +++ b/tests/test_set.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.set diff --git a/tests/test_tokenizer.py b/tests/test_tokenizer.py index 1b09ce23..d833feaf 100644 --- a/tests/test_tokenizer.py +++ b/tests/test_tokenizer.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import dns.exception import dns.tokenizer diff --git a/tests/test_update.py b/tests/test_update.py index 240da005..56ce31dc 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -13,10 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest import binascii import dns.update @@ -63,7 +60,7 @@ blaz2 ANY ANY class UpdateTestCase(unittest.TestCase): - def test_to_wire1(self): + def test_to_wire1(self): # type: () -> None update = dns.update.Update('example') update.id = 1 update.present('foo') @@ -78,7 +75,7 @@ class UpdateTestCase(unittest.TestCase): update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) - def test_to_wire2(self): + def test_to_wire2(self): # type: () -> None update = dns.update.Update('example') update.id = 1 update.present('foo') @@ -93,7 +90,7 @@ class UpdateTestCase(unittest.TestCase): update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) - def test_to_wire3(self): + def test_to_wire3(self): # type: () -> None update = dns.update.Update('example') update.id = 1 update.present('foo') @@ -108,7 +105,7 @@ class UpdateTestCase(unittest.TestCase): update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) - def test_from_text1(self): + def test_from_text1(self): # type: () -> None update = dns.message.from_text(update_text) w = update.to_wire(origin=dns.name.from_text('example'), want_shuffle=False) diff --git a/tests/test_wiredata.py b/tests/test_wiredata.py index eccc3e24..9644de47 100644 --- a/tests/test_wiredata.py +++ b/tests/test_wiredata.py @@ -6,10 +6,7 @@ # provided that the above copyright notice and this permission notice # appear in all copies. -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from dns.exception import FormError from dns.wiredata import WireData diff --git a/tests/test_zone.py b/tests/test_zone.py index ce7caf01..e917fa1f 100644 --- a/tests/test_zone.py +++ b/tests/test_zone.py @@ -16,17 +16,17 @@ from io import BytesIO, StringIO import filecmp import os -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest +from typing import cast import dns.exception import dns.rdata +import dns.rdataset import dns.rdataclass import dns.rdatatype import dns.rrset import dns.zone +import dns.node def here(filename): return os.path.join(os.path.dirname(__file__), filename) @@ -135,7 +135,7 @@ def _rdata_sort(a): class ZoneTestCase(unittest.TestCase): - def testFromFile1(self): + def testFromFile1(self): # type: () -> None z = dns.zone.from_file(here('example'), 'example') ok = False try: @@ -147,7 +147,7 @@ class ZoneTestCase(unittest.TestCase): os.unlink(here('example1.out')) self.failUnless(ok) - def testFromFile2(self): + def testFromFile2(self): # type: () -> None z = dns.zone.from_file(here('example'), 'example', relativize=False) ok = False try: @@ -159,7 +159,7 @@ class ZoneTestCase(unittest.TestCase): os.unlink(here('example2.out')) self.failUnless(ok) - def testToFileTextualStream(self): + def testToFileTextualStream(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) f = StringIO() z.to_file(f) @@ -167,7 +167,7 @@ class ZoneTestCase(unittest.TestCase): f.close() self.assertEqual(out, example_text_output) - def testToFileBinaryStream(self): + def testToFileBinaryStream(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) f = BytesIO() z.to_file(f) @@ -175,7 +175,7 @@ class ZoneTestCase(unittest.TestCase): f.close() self.assertEqual(out, example_text_output.encode()) - def testToFileTextual(self): + def testToFileTextual(self): # type: () -> None z = dns.zone.from_file(here('example'), 'example') try: f = open(here('example3-textual.out'), 'w') @@ -188,7 +188,7 @@ class ZoneTestCase(unittest.TestCase): os.unlink(here('example3-textual.out')) self.failUnless(ok) - def testToFileBinary(self): + def testToFileBinary(self): # type: () -> None z = dns.zone.from_file(here('example'), 'example') try: f = open(here('example3-binary.out'), 'wb') @@ -201,7 +201,7 @@ class ZoneTestCase(unittest.TestCase): os.unlink(here('example3-binary.out')) self.failUnless(ok) - def testToFileFilename(self): + def testToFileFilename(self): # type: () -> None z = dns.zone.from_file(here('example'), 'example') try: z.to_file(here('example3-filename.out')) @@ -212,7 +212,7 @@ class ZoneTestCase(unittest.TestCase): os.unlink(here('example3-filename.out')) self.failUnless(ok) - def testToText(self): + def testToText(self): # type: () -> None z = dns.zone.from_file(here('example'), 'example') ok = False try: @@ -227,7 +227,7 @@ class ZoneTestCase(unittest.TestCase): os.unlink(here('example3.out')) self.failUnless(ok) - def testFromText(self): + def testFromText(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) f = StringIO() names = list(z.nodes.keys()) @@ -237,7 +237,7 @@ class ZoneTestCase(unittest.TestCase): f.write(u'\n') self.assertEqual(f.getvalue(), example_text_output) - def testTorture1(self): + def testTorture1(self): # type: () -> None # # Read a zone containing all our supported RR types, and # for each RR in the zone, convert the rdata into wire format @@ -258,151 +258,151 @@ class ZoneTestCase(unittest.TestCase): origin=o) self.failUnless(rd == rd2) - def testEqual(self): + def testEqual(self): # type: () -> None z1 = dns.zone.from_text(example_text, 'example.', relativize=True) z2 = dns.zone.from_text(example_text_output, 'example.', relativize=True) self.failUnless(z1 == z2) - def testNotEqual1(self): + def testNotEqual1(self): # type: () -> None z1 = dns.zone.from_text(example_text, 'example.', relativize=True) z2 = dns.zone.from_text(something_quite_similar, 'example.', relativize=True) self.failUnless(z1 != z2) - def testNotEqual2(self): + def testNotEqual2(self): # type: () -> None z1 = dns.zone.from_text(example_text, 'example.', relativize=True) z2 = dns.zone.from_text(something_different, 'example.', relativize=True) self.failUnless(z1 != z2) - def testNotEqual3(self): + def testNotEqual3(self): # type: () -> None z1 = dns.zone.from_text(example_text, 'example.', relativize=True) z2 = dns.zone.from_text(something_different, 'example2.', relativize=True) self.failUnless(z1 != z2) - def testFindRdataset1(self): + def testFindRdataset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) rds = z.find_rdataset('@', 'soa') exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') self.failUnless(rds == exrds) - def testFindRdataset2(self): - def bad(): + def testFindRdataset2(self): # type: () -> None + def bad(): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) z.find_rdataset('@', 'loc') self.failUnlessRaises(KeyError, bad) - def testFindRRset1(self): + def testFindRRset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) rrs = z.find_rrset('@', 'soa') exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') self.failUnless(rrs == exrrs) - def testFindRRset2(self): - def bad(): + def testFindRRset2(self): # type: () -> None + def bad(): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) z.find_rrset('@', 'loc') self.failUnlessRaises(KeyError, bad) - def testGetRdataset1(self): + def testGetRdataset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) rds = z.get_rdataset('@', 'soa') exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') self.failUnless(rds == exrds) - def testGetRdataset2(self): + def testGetRdataset2(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) rds = z.get_rdataset('@', 'loc') self.failUnless(rds is None) - def testGetRRset1(self): + def testGetRRset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) rrs = z.get_rrset('@', 'soa') exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') self.failUnless(rrs == exrrs) - def testGetRRset2(self): + def testGetRRset2(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) rrs = z.get_rrset('@', 'loc') self.failUnless(rrs is None) - def testReplaceRdataset1(self): + def testReplaceRdataset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) rdataset = dns.rdataset.from_text('in', 'ns', 300, 'ns3', 'ns4') z.replace_rdataset('@', rdataset) rds = z.get_rdataset('@', 'ns') self.failUnless(rds is rdataset) - def testReplaceRdataset2(self): + def testReplaceRdataset2(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) rdataset = dns.rdataset.from_text('in', 'txt', 300, '"foo"') z.replace_rdataset('@', rdataset) rds = z.get_rdataset('@', 'txt') self.failUnless(rds is rdataset) - def testDeleteRdataset1(self): + def testDeleteRdataset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) z.delete_rdataset('@', 'ns') rds = z.get_rdataset('@', 'ns') self.failUnless(rds is None) - def testDeleteRdataset2(self): + def testDeleteRdataset2(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) z.delete_rdataset('ns1', 'a') node = z.get_node('ns1') self.failUnless(node is None) - def testNodeFindRdataset1(self): + def testNodeFindRdataset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') self.failUnless(rds == exrds) - def testNodeFindRdataset2(self): - def bad(): + def testNodeFindRdataset2(self): # type: () -> None + def bad(): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) self.failUnlessRaises(KeyError, bad) - def testNodeGetRdataset1(self): + def testNodeGetRdataset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') self.failUnless(rds == exrds) - def testNodeGetRdataset2(self): + def testNodeGetRdataset2(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) self.failUnless(rds is None) - def testNodeDeleteRdataset1(self): + def testNodeDeleteRdataset1(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) self.failUnless(rds is None) - def testNodeDeleteRdataset2(self): + def testNodeDeleteRdataset2(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) self.failUnless(rds is None) - def testIterateRdatasets(self): + def testIterateRdatasets(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) ns = [n for n, r in z.iterate_rdatasets('A')] ns.sort() self.failUnless(ns == [dns.name.from_text('ns1', None), dns.name.from_text('ns2', None)]) - def testIterateAllRdatasets(self): + def testIterateAllRdatasets(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) ns = [n for n, r in z.iterate_rdatasets()] ns.sort() @@ -412,7 +412,7 @@ class ZoneTestCase(unittest.TestCase): dns.name.from_text('ns1', None), dns.name.from_text('ns2', None)]) - def testIterateRdatas(self): + def testIterateRdatas(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) l = list(z.iterate_rdatas('A')) l.sort() @@ -426,7 +426,7 @@ class ZoneTestCase(unittest.TestCase): '10.0.0.2'))] self.failUnless(l == exl) - def testIterateAllRdatas(self): + def testIterateAllRdatas(self): # type: () -> None z = dns.zone.from_text(example_text, 'example.', relativize=True) l = list(z.iterate_rdatas()) l.sort(key=_rdata_sort) @@ -457,90 +457,90 @@ class ZoneTestCase(unittest.TestCase): exl.sort(key=_rdata_sort) self.failUnless(l == exl) - def testTTLs(self): + def testTTLs(self): # type: () -> None z = dns.zone.from_text(ttl_example_text, 'example.', relativize=True) - n = z['@'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + n = z['@'] # type: dns.node.Node + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)) self.failUnless(rds.ttl == 3600) n = z['ns1'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) self.failUnless(rds.ttl == 86401) n = z['ns2'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) self.failUnless(rds.ttl == 694861) - def testTTLFromSOA(self): + def testTTLFromSOA(self): # type: () -> None z = dns.zone.from_text(ttl_from_soa_text, 'example.', relativize=True) n = z['@'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)) self.failUnless(rds.ttl == 3600) soa_rd = rds[0] n = z['ns1'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) self.failUnless(rds.ttl == 694861) n = z['ns2'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) self.failUnless(rds.ttl == soa_rd.minimum) - def testTTLFromLast(self): + def testTTLFromLast(self): # type: () -> None z = dns.zone.from_text(ttl_from_last_text, 'example.', check_origin=False) n = z['@'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.NS) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.NS)) self.failUnless(rds.ttl == 3600) n = z['ns1'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) self.failUnless(rds.ttl == 3600) n = z['ns2'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) self.failUnless(rds.ttl == 694861) - def testNoTTL(self): - def bad(): + def testNoTTL(self): # type: () -> None + def bad(): # type: () -> None dns.zone.from_text(no_ttl_text, 'example.', check_origin=False) self.failUnlessRaises(dns.exception.SyntaxError, bad) - def testNoSOA(self): - def bad(): + def testNoSOA(self): # type: () -> None + def bad(): # type: () -> None dns.zone.from_text(no_soa_text, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoSOA, bad) - def testNoNS(self): - def bad(): + def testNoNS(self): # type: () -> None + def bad(): # type: () -> None dns.zone.from_text(no_ns_text, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoNS, bad) - def testInclude(self): + def testInclude(self): # type: () -> None z1 = dns.zone.from_text(include_text, 'example.', relativize=True, allow_include=True) z2 = dns.zone.from_file(here('example'), 'example.', relativize=True) self.failUnless(z1 == z2) - def testBadDirective(self): - def bad(): + def testBadDirective(self): # type: () -> None + def bad(): # type: () -> None dns.zone.from_text(bad_directive_text, 'example.', relativize=True) self.failUnlessRaises(dns.exception.SyntaxError, bad) - def testFirstRRStartsWithWhitespace(self): + def testFirstRRStartsWithWhitespace(self): # type: () -> None # no name is specified, so default to the initial origin z = dns.zone.from_text(' 300 IN A 10.0.0.1', origin='example.', check_origin=False) n = z['@'] - rds = n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A) + rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) self.failUnless(rds.ttl == 300) - def testZoneOrigin(self): + def testZoneOrigin(self): # type: () -> None z = dns.zone.Zone('example.') self.failUnless(z.origin == dns.name.from_text('example.')) - def bad1(): + def bad1(): # type: () -> None o = dns.name.from_text('example', None) dns.zone.Zone(o) self.failUnlessRaises(ValueError, bad1) - def bad2(): - dns.zone.Zone(1.0) + def bad2(): # type: () -> None + dns.zone.Zone(cast(str, 1.0)) self.failUnlessRaises(ValueError, bad2) - def testZoneOriginNone(self): - dns.zone.Zone(None) + def testZoneOriginNone(self): # type: () -> None + dns.zone.Zone(cast(str, None)) if __name__ == '__main__': unittest.main() diff --git a/tests/utest.py b/tests/utest.py index 033b0428..20f8e186 100644 --- a/tests/utest.py +++ b/tests/utest.py @@ -1,9 +1,6 @@ import os.path import sys -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest if __name__ == '__main__': sys.path.insert(0, os.path.realpath('..')) diff --git a/tox.ini b/tox.ini index 54401253..9528c2f9 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,7 @@ envlist = py37, flake8, pylint, + mypy, coverage [testenv] @@ -16,9 +17,9 @@ commands= deps= -[testenv:py26] +[testenv:py27] deps = - unittest2 + typing [testenv:flake8] @@ -31,6 +32,11 @@ commands = pip install pylint pylint dns +[testenv:mypy] +commands = + pip install mypy + mypy examples tests + [testenv:coverage] basepython = python2