public inbox for ddns@lists.ipfire.org
 help / color / mirror / Atom feed
From: Michael Tremer <michael.tremer@ipfire.org>
To: ddns@lists.ipfire.org
Subject: Re: [PATCH] DDNS: Port to python3
Date: Mon, 06 Jan 2020 14:44:25 +0000	[thread overview]
Message-ID: <B338545A-3BC9-4B87-B834-9895A0279F90@ipfire.org> (raw)
In-Reply-To: <3125c3335d44ab24744fe1f9ed75974f1c142d8a.camel@ipfire.org>

[-- Attachment #1: Type: text/plain, Size: 110175 bytes --]



> On 6 Jan 2020, at 12:31, Stefan Schantl <stefan.schantl(a)ipfire.org> wrote:
> 
> Hello Kim,
> 
> thanks for keep working on this and sorry for the long delay.
> 
> Today I had some spare-time and checked your patch.
> 
> Besides there are still some formating issues because of your used
> Editor (New blank lines added, tabs are reformated, intensions are
> changed etc), I was not able to get a list of the supported Providers
> anymore after applying your Patch.

Some of those whitespace changes are required because Python 3 does not allow mixed tabs and spaces in the same line (file?) any more.

> root(a)system:/home/ddns# python3 /usr/bin/ddns -d -c
> /etc/ddns/ddns.conf.sample list-providers
> Debugmodus eingeschaltet
> Laufe auf Distribution: unknown
> Lade Konfigurationsdatei /etc/ddns/ddns.conf.sample
> 
> The output should look like this:
> 
> root(a)system:/home/ddns# python2 /usr/bin/ddns -d -c
> /etc/ddns/ddns.conf.sample list-providers
> Debugmodus eingeschaltet
> Registered new provider: All-inkl.com (all-inkl.com)
> Registered new provider: ChangeIP.com (changeip.com)
> Registered new provider: DDNSS (ddnss.de)
> Registered new provider: desec.io (desec.io)
> Registered new provider: DHS International (dhs.org)
> Registered new provider: Lightning Wire Labs DNS Service
> (dns.lightningwirelabs.com)
> Registered new provider: DNSmadeEasy.com (dnsmadeeasy.com)
> Registered new provider: DNS Park (dnspark.com)
> Registered new provider: Domain-Offensive (do.de)
> Registered new provider: Google Domains (domains.google.com)
> Registered new provider: domopoli.de (domopoli.de)
> Registered new provider: DtDNS (dtdns.com)
> Registered new provider: Duck DNS (duckdns.org)
> Registered new provider: dy.fi (dy.fi)
> Registered new provider: Dyn (dyndns.org)
> Registered new provider: DyNS (dyns.net)
> Registered new provider: Dynu (dynu.com)
> Registered new provider: DynUp.DE (dynup.de)
> Registered new provider: EasyDNS (easydns.com)
> Registered new provider: eNom Inc. (enom.com)
> Registered new provider: EntryDNS (entrydns.net)
> Registered new provider: freedns.afraid.org (freedns.afraid.org)
> Registered new provider: INWX (inwx.com)
> Registered new provider: it's DNS (itsdns.de)
> Registered new provider: Joker.com Dynamic DNS (joker.com)
> Registered new provider: Loopia AB (loopia.se)
> Registered new provider: myonlineportal.net (myonlineportal.net)
> Registered new provider: Namecheap (namecheap.com)
> Registered new provider: No-IP (no-ip.com)
> Registered new provider: NOW-DNS (now-dns.com)
> Registered new provider: BIND nsupdate utility (nsupdate)
> Registered new provider: nsupdate.info (nsupdate.info)
> Registered new provider: OpenDNS (opendns.com)
> Registered new provider: OVH (ovh.com)
> Registered new provider: Regfish GmbH (regfish.com)
> Registered new provider: Schokokeks (schokokeks.org)
> Registered new provider: Selfhost.de (selfhost.de)
> Registered new provider: servercow.de (servercow.de)
> Registered new provider: SPDYN (spdns.org)
> Registered new provider: Strato AG (strato.com)
> Registered new provider: TwoDNS (twodns.de)
> Registered new provider: Udmedia GmbH (udmedia.de)
> Registered new provider: Variomedia (variomedia.de)
> Registered new provider: XLhost (xlhost.de)
> Registered new provider: Zoneedit (zoneedit.com)
> Registered new provider: zzzz (zzzz.io)
> Laufe auf Distribution: unknown
> Lade Konfigurationsdatei /etc/ddns/ddns.conf.sample
> all-inkl.com
> changeip.com
> ddnss.de
> desec.io
> dhs.org
> dns.lightningwirelabs.com
> dnsmadeeasy.com
> dnspark.com
> do.de
> domains.google.com
> domopoli.de
> dtdns.com
> duckdns.org
> dy.fi
> dyndns.org
> dyns.net
> dynu.com
> dynup.de
> easydns.com
> enom.com
> entrydns.net
> freedns.afraid.org
> inwx.com
> itsdns.de
> joker.com
> loopia.se
> myonlineportal.net
> namecheap.com
> no-ip.com
> now-dns.com
> nsupdate
> nsupdate.info
> opendns.com
> ovh.com
> regfish.com
> schokokeks.org
> selfhost.de
> servercow.de
> spdns.org
> strato.com
> twodns.de
> udmedia.de
> variomedia.de
> xlhost.de
> zoneedit.com
> zzzz.io
> 
> Please check your Patch and re-submit a fixed version.
> 
> Many thanks in advance,
> 
> -Stefan
>> Hi together,
>> 
>> Fixed the things Michael mentioned. Update of the headers and
>> .gitignore will follow in a separate patch if we decide it is
>> necessary.
>> 
>> I corrected additionally some intentions and adapted some PEP8 style
>> guidelines 
>> 
>> Greetings
>> Kim
>> 
>> Index: src/ddns/system.py
>> IDEA additional info:
>> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
>> <+>UTF-8
>> ===================================================================
>> --- src/ddns/system.py	(revision
>> c0277eeea2b2c1ed8f40f1248b28438e44e51912)
>> +++ src/ddns/system.py	(date 1577472902318)
>> @@ -1,4 +1,4 @@
>> -#!/usr/bin/python
>> +#!/usr/bin/python3
>> ####################################################################
>> ###########
>> #                                                                  
>>          #
>> # ddns - A dynamic DNS client for IPFire                            
>>         #
>> @@ -23,18 +23,20 @@
>> import re
>> import ssl
>> import socket
>> -import urllib
>> -import urllib2
>> +import urllib.request
>> +import urllib.parse
>> +import urllib.error
>> 
>> -from __version__ import CLIENT_VERSION
>> +from .__version__ import CLIENT_VERSION
>> from .errors import *
>> -from i18n import _
>> +from .i18n import _
>> 
>> # Initialize the logger.
>> import logging
>> logger = logging.getLogger("ddns.system")
>> logger.propagate = 1
>> 
>> +
>> class DDNSSystem(object):
>> 	"""
>> 		The DDNSSystem class adds a layer of abstraction
>> @@ -79,7 +81,7 @@
>> 				with open("/var/ipfire/red/local-
>> ipaddress") as f:
>> 					return f.readline()
>> 
>> -			except IOError, e:
>> +			except IOError as e:
>> 				# File not found
>> 				if e.errno == 2:
>> 					return
>> @@ -137,7 +139,7 @@
>> 		if data:
>> 			logger.debug("  data: %s" % data)
>> 
>> -		req = urllib2.Request(url, data=data)
>> +		req = urllib.request.Request(url, data=data)
>> 
>> 		if username and password:
>> 			basic_auth_header =
>> self._make_basic_auth_header(username, password)
>> @@ -163,7 +165,7 @@
>> 			logger.debug("  %s: %s" % (k, v))
>> 
>> 		try:
>> -			resp = urllib2.urlopen(req, timeout=timeout)
>> +			resp = urllib.request.urlopen(req,
>> timeout=timeout)
>> 
>> 			# Log response header.
>> 			logger.debug(_("Response header (Status Code
>> %s):") % resp.code)
>> @@ -173,7 +175,7 @@
>> 			# Return the entire response object.
>> 			return resp
>> 
>> -		except urllib2.HTTPError, e:
>> +		except urllib.error.HTTPError as e:
>> 			# Log response header.
>> 			logger.debug(_("Response header (Status Code
>> %s):") % e.code)
>> 			for k, v in e.hdrs.items():
>> @@ -209,7 +211,7 @@
>> 			# Raise all other unhandled exceptions.
>> 			raise
>> 
>> -		except urllib2.URLError, e:
>> +		except urllib.error.URLError as e:
>> 			if e.reason:
>> 				# Handle SSL errors
>> 				if isinstance(e.reason, ssl.SSLError):
>> @@ -240,7 +242,7 @@
>> 			# Raise all other unhandled exceptions.
>> 			raise
>> 
>> -		except socket.timeout, e:
>> +		except socket.timeout as e:
>> 			logger.debug(_("Connection timeout"))
>> 
>> 			raise DDNSConnectionTimeoutError
>> @@ -249,7 +251,7 @@
>> 		args = []
>> 
>> 		for k, v in data.items():
>> -			arg = "%s=%s" % (k, urllib.quote(v))
>> +			arg = "%s=%s" % (k, urllib.parse.quote(v))
>> 			args.append(arg)
>> 
>> 		return "&".join(args)
>> @@ -258,7 +260,7 @@
>> 		authstring = "%s:%s" % (username, password)
>> 
>> 		# Encode authorization data in base64.
>> -		authstring = base64.encodestring(authstring)
>> +		authstring = base64.encodebytes(authstring)
>> 
>> 		# Remove any newline characters.
>> 		authstring = authstring.replace("\n", "")
>> @@ -354,7 +356,7 @@
>> 		# Resolve the host address.
>> 		try:
>> 			response = socket.getaddrinfo(hostname, None,
>> family)
>> -		except socket.gaierror, e:
>> +		except socket.gaierror as e:
>> 			# Name or service not known
>> 			if e.errno == -2:
>> 				return []
>> @@ -388,7 +390,7 @@
>> 				continue
>> 
>> 			# Add to repsonse list if not already in there.
>> -			if not address in addresses:
>> +			if address not in addresses:
>> 				addresses.append(address)
>> 
>> 		return addresses
>> @@ -418,7 +420,7 @@
>> 		"""
>> 		try:
>> 			f = open("/etc/os-release", "r")
>> -		except IOError, e:
>> +		except IOError as e:
>> 			# File not found
>> 			if e.errno == 2:
>> 				return
>> @@ -447,7 +449,7 @@
>> 		"""
>> 		try:
>> 			f = open("/etc/system-release", "r")
>> -		except IOError, e:
>> +		except IOError as e:
>> 			# File not found
>> 			if e.errno == 2:
>> 				return
>> Index: src/ddns/i18n.py
>> IDEA additional info:
>> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
>> <+>UTF-8
>> ===================================================================
>> --- src/ddns/i18n.py	(revision
>> c0277eeea2b2c1ed8f40f1248b28438e44e51912)
>> +++ src/ddns/i18n.py	(date 1577472902317)
>> @@ -1,4 +1,4 @@
>> -#!/usr/bin/python
>> +#!/usr/bin/python3
>> ####################################################################
>> ###########
>> #                                                                  
>>          #
>> # ddns - A dynamic DNS client for IPFire                            
>>         #
>> @@ -25,15 +25,14 @@
>> 
>> N_ = lambda x: x
>> 
>> +
>> def _(singular, plural=None, n=None):
>> 	"""
>> 		A function that returnes the translation of a string if
>> available.
>> -
>> 		The language is taken from the system environment.
>> -        """
>> -	if not plural is None:
>> +	"""
>> +	if plural is not None:
>> 		assert n is not None
>> 		return gettext.dngettext(TEXTDOMAIN, singular, plural,
>> n)
>> 
>> 	return gettext.dgettext(TEXTDOMAIN, singular)
>> -
>> Index: configure.ac
>> IDEA additional info:
>> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
>> <+>UTF-8
>> ===================================================================
>> --- configure.ac	(revision
>> c0277eeea2b2c1ed8f40f1248b28438e44e51912)
>> +++ configure.ac	(date 1577473544755)
>> @@ -21,7 +21,7 @@
>> AC_PREREQ([2.64])
>> 
>> AC_INIT([ddns],
>> -	[012],
>> +	[013],
>> 	[info(a)ipfire.org],
>> 	[ddns],
>> 	[http://git.ipfire.org/?p=oddments/ddns.git;a=summary])
>> @@ -54,7 +54,7 @@
>> AC_PATH_PROG([XSLTPROC], [xsltproc])
>> 
>> # Python
>> -AM_PATH_PYTHON([2.7])
>> +AM_PATH_PYTHON([3.6])
>> 
>> save_LIBS="$LIBS"
>> 
>> Index: ddns.in
>> IDEA additional info:
>> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
>> <+>UTF-8
>> ===================================================================
>> --- ddns.in	(revision c0277eeea2b2c1ed8f40f1248b28438e44e51912)
>> +++ ddns.in	(date 1577472902316)
>> @@ -1,4 +1,4 @@
>> -#!/usr/bin/python
>> +#!/usr/bin/python3
>> ####################################################################
>> ###########
>> #                                                                  
>>          #
>> # ddns - A dynamic DNS client for IPFire                            
>>         #
>> @@ -27,27 +27,24 @@
>> 
>> CONFIGURATION_FILE = "@configsdir@/ddns.conf"
>> 
>> +
>> def main():
>> 	# Parse command line
>> 	p = argparse.ArgumentParser(description=_("Dynamic DNS
>> Updater"))
>> 
>> -	p.add_argument("-d", "--debug", action="store_true",
>> -		help=_("Enable debugging output"))
>> +	p.add_argument("-d", "--debug", action="store_true",
>> help=_("Enable debugging output"))
>> 
>> 	p.add_argument("-c", "--config", default=CONFIGURATION_FILE,
>> 		help=_("Load configuration file (Default: %s)") %
>> CONFIGURATION_FILE)
>> 
>> 	# Create subparsers for commands.
>> -	subparsers = p.add_subparsers(help=_("Sub-command help"),
>> -		dest="subparsers_name")
>> +	subparsers = p.add_subparsers(help=_("Sub-command help"),
>> dest="subparsers_name")
>> 
>> 	# guess-ip-addresses
>> -	p_guess_ip_addresses = subparsers.add_parser("guess-ip-
>> addresses",
>> -		help=_("Guess the external IP addresses"))
>> +	p_guess_ip_addresses = subparsers.add_parser("guess-ip-
>> addresses", help=_("Guess the external IP addresses"))
>> 
>> 	# list-providers
>> -	p_list_providers = subparsers.add_parser("list-providers",
>> -		help=_("List all available providers"))
>> +	p_list_providers = subparsers.add_parser("list-providers",
>> help=_("List all available providers"))
>> 
>> 	# update
>> 	p_update = subparsers.add_parser("update", help=_("Update DNS
>> record"))
>> @@ -74,16 +71,16 @@
>> 		# IPv6
>> 		ipv6_address =
>> d.system.guess_external_ip_address("ipv6")
>> 		if ipv6_address:
>> -			print _("IPv6 Address: %s") % ipv6_address
>> +			print("IPv6 Address: %s" % ipv6_address)
>> 
>> 		# IPv4
>> 		ipv4_address =
>> d.system.guess_external_ip_address("ipv4")
>> 		if ipv4_address:
>> -			print _("IPv4 Address: %s") % ipv4_address
>> +			print("IPv4 Address: %s" % ipv4_address)
>> 
>> 	elif args.subparsers_name == "list-providers":
>> 		provider_names = d.get_provider_names()
>> -		print "\n".join(provider_names)
>> +		print("\n".join(provider_names))
>> 
>> 	elif args.subparsers_name == "update":
>> 		d.updateone(hostname=args.hostname, force=args.force)
>> @@ -94,4 +91,5 @@
>> 	else:
>> 		raise RuntimeError("Unhandled command: %s" %
>> args.subparsers_name)
>> 
>> +
>> main()
>> Index: src/ddns/database.py
>> IDEA additional info:
>> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
>> <+>UTF-8
>> ===================================================================
>> --- src/ddns/database.py	(revision
>> c0277eeea2b2c1ed8f40f1248b28438e44e51912)
>> +++ src/ddns/database.py	(date 1577472902317)
>> @@ -1,4 +1,4 @@
>> -#!/usr/bin/python
>> +#!/usr/bin/python3
>> ####################################################################
>> ###########
>> #                                                                  
>>          #
>> # ddns - A dynamic DNS client for IPFire                            
>>         #
>> @@ -28,6 +28,7 @@
>> logger = logging.getLogger("ddns.database")
>> logger.propagate = 1
>> 
>> +
>> class DDNSDatabase(object):
>> 	def __init__(self, core, path):
>> 		self.core = core
>> @@ -82,6 +83,7 @@
>> 
>> 	def _close_database(self):
>> 		if self._db:
>> +			# TODO: Check Unresolved attribute reference
>> '_db_close' for class 'DDNSDatabase'
>> 			self._db_close()
>> 			self._db = None
>> 
>> Index: src/ddns/providers.py
>> IDEA additional info:
>> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
>> <+>UTF-8
>> ===================================================================
>> --- src/ddns/providers.py	(revision
>> c0277eeea2b2c1ed8f40f1248b28438e44e51912)
>> +++ src/ddns/providers.py	(date 1577472902318)
>> @@ -1,4 +1,4 @@
>> -#!/usr/bin/python
>> +#!/usr/bin/python3
>> ####################################################################
>> ###########
>> #                                                                  
>>          #
>> # ddns - A dynamic DNS client for IPFire                            
>>         #
>> @@ -23,10 +23,12 @@
>> import logging
>> import os
>> import subprocess
>> -import urllib2
>> +import urllib.request
>> +import urllib.error
>> +import urllib.parse
>> import xml.dom.minidom
>> 
>> -from i18n import _
>> +from .i18n import _
>> 
>> # Import all possible exception types.
>> from .errors import *
>> @@ -36,12 +38,14 @@
>> 
>> _providers = {}
>> 
>> +
>> def get():
>> 	"""
>> 		Returns a dict with all automatically registered
>> providers.
>> 	"""
>> 	return _providers.copy()
>> 
>> +
>> class DDNSProvider(object):
>> 	# A short string that uniquely identifies
>> 	# this provider.
>> @@ -84,7 +88,7 @@
>> 			if not all((provider.handle, provider.name,
>> provider.website)):
>> 				raise DDNSError(_("Provider is not
>> properly configured"))
>> 
>> -			assert not _providers.has_key(provider.handle),
>> \
>> +			assert provider.handle not in _providers, \
>> 				"Provider '%s' has already been
>> registered" % provider.handle
>> 
>> 			_providers[provider.handle] = provider
>> @@ -109,7 +113,7 @@
>> 		return "<DDNS Provider %s (%s)>" % (self.name,
>> self.handle)
>> 
>> 	def __cmp__(self, other):
>> -		return cmp(self.hostname, other.hostname)
>> +		return (lambda a, b: (a > b)-(a < b))(self.hostname,
>> other.hostname)
>> 
>> 	@property
>> 	def db(self):
>> @@ -176,8 +180,8 @@
>> 			self.core.db.log_failure(self.hostname, e)
>> 			raise
>> 
>> -		logger.info(_("Dynamic DNS update for %(hostname)s
>> (%(provider)s) successful") % \
>> -			{ "hostname" : self.hostname, "provider" :
>> self.name })
>> +		logger.info(_("Dynamic DNS update for %(hostname)s
>> (%(provider)s) successful") %
>> +					{"hostname": self.hostname,
>> "provider": self.name})
>> 		self.core.db.log_success(self.hostname)
>> 
>> 	def update(self):
>> @@ -192,7 +196,7 @@
>> 
>> 	def remove_protocol(self, proto):
>> 		if not self.can_remove_records:
>> -			raise RuntimeError, "can_remove_records is
>> enabled, but remove_protocol() not implemented"
>> +			raise RuntimeError("can_remove_records is
>> enabled, but remove_protocol() not implemented")
>> 
>> 		raise NotImplementedError
>> 
>> @@ -200,23 +204,21 @@
>> 	def requires_update(self):
>> 		# If the IP addresses have changed, an update is
>> required
>> 		if self.ip_address_changed(self.protocols):
>> -			logger.debug(_("An update for %(hostname)s
>> (%(provider)s)"
>> -				" is performed because of an IP address
>> change") % \
>> -				{ "hostname" : self.hostname,
>> "provider" : self.name })
>> +			logger.debug(_("An update for %(hostname)s
>> (%(provider)s) is performed because of an IP address change") %
>> +			{"hostname": self.hostname, "provider":
>> self.name})
>> 
>> 			return True
>> 
>> 		# If the holdoff time has expired, an update is
>> required, too
>> 		if self.holdoff_time_expired():
>> -			logger.debug(_("An update for %(hostname)s
>> (%(provider)s)"
>> -				" is performed because the holdoff time
>> has expired") % \
>> -				{ "hostname" : self.hostname,
>> "provider" : self.name })
>> +			logger.debug(_("An update for %(hostname)s
>> (%(provider)s) is performed because the holdoff time has expired") %
>> +						 {"hostname":
>> self.hostname, "provider": self.name})
>> 
>> 			return True
>> 
>> 		# Otherwise, we don't need to perform an update
>> -		logger.debug(_("No update required for %(hostname)s
>> (%(provider)s)") % \
>> -			{ "hostname" : self.hostname, "provider" :
>> self.name })
>> +		logger.debug(_("No update required for %(hostname)s
>> (%(provider)s)") %
>> +					 {"hostname": self.hostname,
>> "provider": self.name})
>> 
>> 		return False
>> 
>> @@ -234,8 +236,7 @@
>> 
>> 		# If there is no holdoff time, we won't update ever
>> again.
>> 		if self.holdoff_failure_days is None:
>> -			logger.warning(_("An update has not been
>> performed because earlier updates failed for %s") \
>> -				% self.hostname)
>> +			logger.warning(_("An update has not been
>> performed because earlier updates failed for %s") % self.hostname)
>> 			logger.warning(_("There will be no retries"))
>> 
>> 			return True
>> @@ -248,8 +249,7 @@
>> 		if now < holdoff_end:
>> 			failure_message =
>> self.db.last_update_failure_message(self.hostname)
>> 
>> -			logger.warning(_("An update has not been
>> performed because earlier updates failed for %s") \
>> -				% self.hostname)
>> +			logger.warning(_("An update has not been
>> performed because earlier updates failed for %s") % self.hostname)
>> 
>> 			if failure_message:
>> 				logger.warning(_("Last failure
>> message:"))
>> @@ -315,8 +315,8 @@
>> 			logger.debug("The holdoff time has expired for
>> %s" % self.hostname)
>> 			return True
>> 		else:
>> -			logger.debug("Updates for %s are held off until
>> %s" % \
>> -				(self.hostname, holdoff_end))
>> +			logger.debug("Updates for %s are held off until
>> %s" %
>> +						 (self.hostname,
>> holdoff_end))
>> 			return False
>> 
>> 	def send_request(self, *args, **kwargs):
>> @@ -362,8 +362,8 @@
>> 
>> 	def prepare_request_data(self, proto):
>> 		data = {
>> -			"hostname" : self.hostname,
>> -			"myip"     : self.get_address(proto),
>> +			"hostname": self.hostname,
>> +			"myip": self.get_address(proto),
>> 		}
>> 
>> 		return data
>> @@ -375,8 +375,7 @@
>> 
>> 	def send_request(self, data):
>> 		# Send update to the server.
>> -		response = DDNSProvider.send_request(self, self.url,
>> data=data,
>> -			username=self.username, password=self.password)
>> +		response = DDNSProvider.send_request(self, self.url,
>> data=data, username=self.username, password=self.password)
>> 
>> 		# Get the full response message.
>> 		output = response.read()
>> @@ -413,7 +412,7 @@
>> 		will be sent by various providers. This class uses the
>> python
>> 		shipped XML minidom module to walk through the XML tree
>> and return
>> 		a requested element.
>> -        """
>> +	"""
>> 
>> 	def get_xml_tag_value(self, document, content):
>> 		# Send input to the parser.
>> @@ -494,9 +493,7 @@
>> 		# -t sets the timeout
>> 		command = ["nsupdate", "-v", "-t", "60"]
>> 
>> -		p = subprocess.Popen(command, shell=True,
>> -			stdin=subprocess.PIPE, stdout=subprocess.PIPE,
>> stderr=subprocess.PIPE,
>> -		)
>> +		p = subprocess.Popen(command, shell=True,
>> stdin=subprocess.PIPE, stdout=subprocess.PIPE,
>> stderr=subprocess.PIPE)
>> 		stdout, stderr = p.communicate(scriptlet)
>> 
>> 		if p.returncode == 0:
>> @@ -533,7 +530,7 @@
>> 
>> 			scriptlet.append("update delete %s. %s" %
>> (self.hostname, rrtype))
>> 			scriptlet.append("update add %s. %s %s %s" % \
>> -				(self.hostname, ttl, rrtype, address))
>> +							 (self.hostname
>> , ttl, rrtype, address))
>> 
>> 		# Send the actions to the server.
>> 		scriptlet.append("send")
>> @@ -570,11 +567,10 @@
>> 
>> 		# Send update to the server.
>> 		try:
>> -			response = self.send_request(self.url,
>> username=self.username, password=self.password,
>> -				data=data)
>> +			response = self.send_request(self.url,
>> username=self.username, password=self.password, data=data)
>> 
>> 		# Handle error codes.
>> -		except urllib2.HTTPError, e:
>> +		except urllib.error.HTTPError as e:
>> 			if e.code == 422:
>> 				raise DDNSRequestError(_("Domain not
>> found."))
>> 
>> @@ -585,7 +581,7 @@
>> 			return
>> 
>> 		# If we got here, some other update error happened.
>> -		raise DDNSUpdateError(_("Server response: %s") %
>> output)
>> +		raise DDNSUpdateError(_("Server response: %s") %
>> response)
>> 
>> 
>> class DDNSProviderDesecIO(DDNSProtocolDynDNS2, DDNSProvider):
>> @@ -631,8 +627,8 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"ip"   : self.get_address(proto),
>> -			"host" : self.hostname,
>> +			"ip": self.get_address(proto),
>> +			"host": self.hostname,
>> 		}
>> 
>> 		# Check if a token has been set.
>> @@ -642,8 +638,8 @@
>> 		# Check if username and hostname are given.
>> 		elif self.username and self.password:
>> 			data.update({
>> -				"user" : self.username,
>> -				"pwd"  : self.password,
>> +				"user": self.username,
>> +				"pwd": self.password,
>> 			})
>> 
>> 		# Raise an error if no auth details are given.
>> @@ -695,16 +691,15 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"domain"       : self.hostname,
>> -			"ip"           : self.get_address(proto),
>> -			"hostcmd"      : "edit",
>> -			"hostcmdstage" : "2",
>> -			"type"         : "4",
>> +			"domain": self.hostname,
>> +			"ip": self.get_address(proto),
>> +			"hostcmd": "edit",
>> +			"hostcmdstage": "2",
>> +			"type": "4",
>> 		}
>> 
>> 		# Send update to the server.
>> -		response = self.send_request(self.url,
>> username=self.username, password=self.password,
>> -			data=data)
>> +		response = self.send_request(self.url,
>> username=self.username, password=self.password, data=data)
>> 
>> 		# Handle success messages.
>> 		if response.code == 200:
>> @@ -728,13 +723,12 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"domain" : self.hostname,
>> -			"ip"     : self.get_address(proto),
>> +			"domain": self.hostname,
>> +			"ip": self.get_address(proto),
>> 		}
>> 
>> 		# Send update to the server.
>> -		response = self.send_request(self.url,
>> username=self.username, password=self.password,
>> -			data=data)
>> +		response = self.send_request(self.url,
>> username=self.username, password=self.password, data=data)
>> 
>> 		# Get the full response message.
>> 		output = response.read()
>> @@ -777,9 +771,9 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"ip" : self.get_address(proto),
>> -			"id" : self.hostname,
>> -			"pw" : self.password
>> +			"ip": self.get_address(proto),
>> +			"id": self.hostname,
>> +			"pw": self.password
>> 		}
>> 
>> 		# Send update to the server.
>> @@ -873,6 +867,7 @@
>> 
>> 	url = "https://ddns.do.de/"
>> 
>> +
>> class DDNSProviderDynUp(DDNSProvider):
>> 	handle    = "dynup.de"
>> 	name      = "DynUp.DE"
>> @@ -887,10 +882,10 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"username" : self.username,
>> -			"password" : self.password,
>> -			"hostname" : self.hostname,
>> -			"print" : '1',
>> +			"username": self.username,
>> +			"password": self.password,
>> +			"hostname": self.hostname,
>> +			"print": '1',
>> 		}
>> 
>> 		# Send update to the server.
>> @@ -903,14 +898,13 @@
>> 		output = output.strip()
>> 
>> 		# Handle success messages.
>> -		if output.startswith("I:OK") :
>> +		if output.startswith("I:OK"):
>> 			return
>> 
>> 		# If we got here, some other update error happened.
>> 		raise DDNSUpdateError
>> 
>> 
>> -
>> class DDNSProviderDynU(DDNSProtocolDynDNS2, DDNSProvider):
>> 	handle    = "dynu.com"
>> 	name      = "Dynu"
>> @@ -952,13 +946,12 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"myip"     : self.get_address(proto, "-"),
>> -			"hostname" : self.hostname,
>> +			"myip": self.get_address(proto, "-"),
>> +			"hostname": self.hostname,
>> 		}
>> 
>> 		# Send update to the server.
>> -		response = self.send_request(self.url, data=data,
>> -			username=self.username, password=self.password)
>> +		response = self.send_request(self.url, data=data,
>> username=self.username, password=self.password)
>> 
>> 		# Get the full response message.
>> 		output = response.read()
>> @@ -1058,11 +1051,11 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"command"        : "setdnshost",
>> -			"responsetype"   : "xml",
>> -			"address"        : self.get_address(proto),
>> -			"domainpassword" : self.password,
>> -			"zone"           : self.hostname
>> +			"command": "setdnshost",
>> +			"responsetype": "xml",
>> +			"address": self.get_address(proto),
>> +			"domainpassword": self.password,
>> +			"zone": self.hostname
>> 		}
>> 
>> 		# Send update to the server.
>> @@ -1100,7 +1093,7 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"ip" : self.get_address(proto),
>> +			"ip": self.get_address(proto),
>> 		}
>> 
>> 		# Add auth token to the update url.
>> @@ -1111,7 +1104,7 @@
>> 			response = self.send_request(url, data=data)
>> 
>> 		# Handle error codes
>> -		except urllib2.HTTPError, e:
>> +		except urllib.error.HTTPError as e:
>> 			if e.code == 404:
>> 				raise DDNSAuthenticationError
>> 
>> @@ -1140,7 +1133,7 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"address" : self.get_address(proto),
>> +			"address": self.get_address(proto),
>> 		}
>> 
>> 		# Add auth token to the update url.
>> @@ -1167,53 +1160,53 @@
>> 
>> 
>> class DDNSProviderItsdns(DDNSProtocolDynDNS2, DDNSProvider):
>> -		handle    = "inwx.com"
>> -		name      = "INWX"
>> -		website   = "https://www.inwx.com"
>> -		protocols = ("ipv6", "ipv4")
>> +	handle    = "inwx.com"
>> +	name      = "INWX"
>> +	website   = "https://www.inwx.com"
>> +	protocols = ("ipv6", "ipv4")
>> 
>> -		# Information about the format of the HTTP request is
>> to be found
>> -		# here: https://www.inwx.com/en/nameserver2/dyndns
>> (requires login)
>> -		# Notice: The URL is the same for: inwx.com|de|at|ch|es
>> +	# Information about the format of the HTTP request is to be
>> found
>> +	# here: https://www.inwx.com/en/nameserver2/dyndns (requires
>> login)
>> +	# Notice: The URL is the same for: inwx.com|de|at|ch|es
>> 
>> -		url = "https://dyndns.inwx.com/nic/update"
>> +	url = "https://dyndns.inwx.com/nic/update"
>> 
>> 
>> class DDNSProviderItsdns(DDNSProtocolDynDNS2, DDNSProvider):
>> -		handle    = "itsdns.de"
>> -		name      = "it's DNS"
>> -		website   = "http://www.itsdns.de/"
>> -		protocols = ("ipv6", "ipv4")
>> +	handle    = "itsdns.de"
>> +	name      = "it's DNS"
>> +	website   = "http://www.itsdns.de/"
>> +	protocols = ("ipv6", "ipv4")
>> 
>> -		# Information about the format of the HTTP request is
>> to be found
>> -		# here: https://www.itsdns.de/dynupdatehelp.htm
>> +	# Information about the format of the HTTP request is to be
>> found
>> +	# here: https://www.itsdns.de/dynupdatehelp.htm
>> 
>> -		url = "https://www.itsdns.de/update.php"
>> +	url = "https://www.itsdns.de/update.php"
>> 
>> 
>> class DDNSProviderJoker(DDNSProtocolDynDNS2, DDNSProvider):
>> -		handle  = "joker.com"
>> -		name    = "Joker.com Dynamic DNS"
>> -		website = "https://joker.com/"
>> -		protocols = ("ipv4",)
>> +	handle  = "joker.com"
>> +	name    = "Joker.com Dynamic DNS"
>> +	website = "https://joker.com/"
>> +	protocols = ("ipv4",)
>> 
>> -		# Information about the request can be found here:
>> -		# 
>> https://joker.com/faq/content/11/427/en/what-is-dynamic-dns-dyndns.html
>> -		# Using DynDNS V2 protocol over HTTPS here
>> +	# Information about the request can be found here:
>> +	# 
>> https://joker.com/faq/content/11/427/en/what-is-dynamic-dns-dyndns.html
>> +	# Using DynDNS V2 protocol over HTTPS here
>> 
>> -		url = "https://svc.joker.com/nic/update"
>> +	url = "https://svc.joker.com/nic/update"
>> 
>> 
>> class DDNSProviderGoogle(DDNSProtocolDynDNS2, DDNSProvider):
>> -        handle    = "domains.google.com"
>> -        name      = "Google Domains"
>> -        website   = "https://domains.google.com/"
>> -        protocols = ("ipv4",)
>> +	handle    = "domains.google.com"
>> +	name      = "Google Domains"
>> +	website   = "https://domains.google.com/"
>> +	protocols = ("ipv4",)
>> 
>> -        # Information about the format of the HTTP request is to be
>> found
>> -        # here: 
>> https://support.google.com/domains/answer/6147083?hl=en
>> +	# Information about the format of the HTTP request is to be
>> found
>> +	# here: https://support.google.com/domains/answer/6147083?hl=en
>> 
>> -        url = "https://domains.google.com/nic/update"
>> +	url = "https://domains.google.com/nic/update"
>> 
>> 
>> class DDNSProviderLightningWireLabs(DDNSProvider):
>> @@ -1227,10 +1220,10 @@
>> 	url = "https://dns.lightningwirelabs.com/update"
>> 
>> 	def update(self):
>> -		data =  {
>> -			"hostname" : self.hostname,
>> -			"address6" : self.get_address("ipv6", "-"),
>> -			"address4" : self.get_address("ipv4", "-"),
>> +		data = {
>> +			"hostname": self.hostname,
>> +			"address6": self.get_address("ipv6", "-"),
>> +			"address4": self.get_address("ipv4", "-"),
>> 		}
>> 
>> 		# Check if a token has been set.
>> @@ -1240,8 +1233,8 @@
>> 		# Check for username and password.
>> 		elif self.username and self.password:
>> 			data.update({
>> -				"username" : self.username,
>> -				"password" : self.password,
>> +				"username": self.username,
>> +				"password": self.password,
>> 			})
>> 
>> 		# Raise an error if no auth details are given.
>> @@ -1283,8 +1276,8 @@
>> 
>> 	def prepare_request_data(self, proto):
>> 		data = {
>> -			"hostname" : self.hostname,
>> -			"ip"     : self.get_address(proto),
>> +			"hostname": self.hostname,
>> +			"ip": self.get_address(proto),
>> 		}
>> 
>> 		return data
>> @@ -1311,10 +1304,10 @@
>> 		address = self.get_address(proto)
>> 
>> 		data = {
>> -			"ip"       : address,
>> -			"password" : self.password,
>> -			"host"     : host,
>> -			"domain"   : domain
>> +			"ip": address,
>> +			"password": self.password,
>> +			"host": host,
>> +			"domain": domain
>> 		}
>> 
>> 		# Send update to the server.
>> @@ -1359,8 +1352,8 @@
>> 		assert proto == "ipv4"
>> 
>> 		data = {
>> -			"hostname" : self.hostname,
>> -			"address"  : self.get_address(proto),
>> +			"hostname": self.hostname,
>> +			"address": self.get_address(proto),
>> 		}
>> 
>> 		return data
>> @@ -1411,7 +1404,7 @@
>> 
>> 	def prepare_request_data(self, proto):
>> 		data = {
>> -			"myip" : self.get_address(proto),
>> +			"myip": self.get_address(proto),
>> 		}
>> 
>> 		return data
>> @@ -1430,8 +1423,8 @@
>> 
>> 	def prepare_request_data(self, proto):
>> 		data = {
>> -			"hostname" : self.hostname,
>> -			"myip"     : self.get_address(proto),
>> +			"hostname": self.hostname,
>> +			"myip": self.get_address(proto),
>> 		}
>> 
>> 		return data
>> @@ -1454,7 +1447,7 @@
>> 	def prepare_request_data(self, proto):
>> 		data = DDNSProtocolDynDNS2.prepare_request_data(self,
>> proto)
>> 		data.update({
>> -			"system" : "dyndns",
>> +			"system": "dyndns",
>> 		})
>> 
>> 		return data
>> @@ -1474,7 +1467,7 @@
>> 
>> 	def update(self):
>> 		data = {
>> -			"fqdn" : self.hostname,
>> +			"fqdn": self.hostname,
>> 		}
>> 
>> 		# Check if we update an IPv6 address.
>> @@ -1488,7 +1481,7 @@
>> 			data["ipv4"] = address4
>> 
>> 		# Raise an error if none address is given.
>> -		if not data.has_key("ipv6") and not
>> data.has_key("ipv4"):
>> +		if "ipv6" not in data and "ipv4" not in data:
>> 			raise DDNSConfigurationError
>> 
>> 		# Check if a token has been set.
>> @@ -1506,8 +1499,7 @@
>> 			response = self.send_request(self.url,
>> data=data)
>> 		else:
>> 			# Send update to the server.
>> -			response = self.send_request(self.url,
>> username=self.username, password=self.password,
>> -				data=data)
>> +			response = self.send_request(self.url,
>> username=self.username, password=self.password, data=data)
>> 
>> 		# Get the full response message.
>> 		output = response.read()
>> @@ -1554,7 +1546,7 @@
>> 	def prepare_request_data(self, proto):
>> 		data = DDNSProtocolDynDNS2.prepare_request_data(self,
>> proto)
>> 		data.update({
>> -			"hostname" : "1",
>> +			"hostname": "1",
>> 		})
>> 
>> 		return data
>> @@ -1571,10 +1563,10 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"ipaddr"   : self.get_address(proto),
>> -			"hostname" : self.hostname,
>> -			"username" : self.username,
>> -			"pass"     : self.password,
>> +			"ipaddr": self.get_address(proto),
>> +			"hostname": self.hostname,
>> +			"username": self.username,
>> +			"pass": self.password,
>> 		}
>> 
>> 		# Send request to provider
>> @@ -1632,8 +1624,8 @@
>> 	def prepare_request_data(self, proto):
>> 		data = DDNSProtocolDynDNS2.prepare_request_data(self,
>> proto)
>> 		data.update({
>> -			"mx" : "NOCHG",
>> -			"backupmx" : "NOCHG"
>> +			"mx": "NOCHG",
>> +			"backupmx": "NOCHG"
>> 		})
>> 
>> 		return data
>> @@ -1655,8 +1647,8 @@
>> 		assert proto == "ipv4"
>> 
>> 		data = {
>> -			"ip"       : self.get_address(proto),
>> -			"hostname" : self.hostname
>> +			"ip": self.get_address(proto),
>> +			"hostname": self.hostname
>> 		}
>> 
>> 		return data
>> @@ -1687,23 +1679,23 @@
>> 
>> 	def prepare_request_data(self, proto):
>> 		data = {
>> -			"hostname" : self.hostname,
>> -			"myip"     : self.get_address(proto),
>> +			"hostname": self.hostname,
>> +			"myip": self.get_address(proto),
>> 		}
>> 
>> 		return data
>> 
>> 
>> class DDNSProviderXLhost(DDNSProtocolDynDNS2, DDNSProvider):
>> -        handle    = "xlhost.de"
>> -        name	  = "XLhost"
>> -        website   = "http://xlhost.de/"
>> -        protocols = ("ipv4",)
>> +	handle    = "xlhost.de"
>> +	name	  = "XLhost"
>> +	website   = "http://xlhost.de/"
>> +	protocols = ("ipv4",)
>> 
>> -        # Information about the format of the HTTP request is to be
>> found
>> -        # here: 
>> https://xlhost.de/faq/index_html?topicId=CQA2ELIPO4SQ
>> +	# Information about the format of the HTTP request is to be
>> found
>> +	# here: https://xlhost.de/faq/index_html?topicId=CQA2ELIPO4SQ
>> 
>> -        url = "https://nsupdate.xlhost.de/"
>> +	url = "https://nsupdate.xlhost.de/"
>> 
>> 
>> class DDNSProviderZoneedit(DDNSProvider):
>> @@ -1721,13 +1713,12 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"dnsto" : self.get_address(proto),
>> -			"host"  : self.hostname
>> +			"dnsto": self.get_address(proto),
>> +			"host": self.hostname
>> 		}
>> 
>> 		# Send update to the server.
>> -		response = self.send_request(self.url,
>> username=self.username, password=self.password,
>> -			data=data)
>> +		response = self.send_request(self.url,
>> username=self.username, password=self.password, data=data)
>> 
>> 		# Get the full response message.
>> 		output = response.read()
>> @@ -1763,10 +1754,10 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"ip" : self.get_address(proto),
>> -			"id" : self.hostname,
>> -			"username" : self.username,
>> -			"password" : self.password,
>> +			"ip": self.get_address(proto),
>> +			"id": self.hostname,
>> +			"username": self.username,
>> +			"password": self.password,
>> 		}
>> 
>> 		# Send update to the server.
>> @@ -1813,8 +1804,8 @@
>> 
>> 	def update_protocol(self, proto):
>> 		data = {
>> -			"ip"    : self.get_address(proto),
>> -			"token" : self.token,
>> +			"ip": self.get_address(proto),
>> +			"token": self.token,
>> 		}
>> 
>> 		if proto == "ipv6":
>> Index: src/ddns/__init__.py
>> IDEA additional info:
>> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
>> <+>UTF-8
>> ===================================================================
>> --- src/ddns/__init__.py	(revision
>> c0277eeea2b2c1ed8f40f1248b28438e44e51912)
>> +++ src/ddns/__init__.py	(date 1577472902316)
>> @@ -1,4 +1,4 @@
>> -#!/usr/bin/python
>> +#!/usr/bin/python3
>> ####################################################################
>> ###########
>> #                                                                  
>>          #
>> # ddns - A dynamic DNS client for IPFire                            
>>         #
>> @@ -21,19 +21,20 @@
>> 
>> import logging
>> import logging.handlers
>> -import ConfigParser
>> +import configparser
>> 
>> -from i18n import _
>> +from .i18n import _
>> 
>> logger = logging.getLogger("ddns.core")
>> logger.propagate = 1
>> 
>> -import database
>> -import providers
>> +from . import database
>> +from . import providers
>> 
>> from .errors import *
>> from .system import DDNSSystem
>> 
>> +
>> # Setup the logger.
>> def setup_logging():
>> 	rootlogger = logging.getLogger("ddns")
>> @@ -51,8 +52,10 @@
>> 	handler = logging.StreamHandler()
>> 	rootlogger.addHandler(handler)
>> 
>> +
>> setup_logging()
>> 
>> +
>> class DDNSCore(object):
>> 	def __init__(self, debug=False):
>> 		# In debug mode, enable debug logging.
>> @@ -89,7 +92,7 @@
>> 	def load_configuration(self, filename):
>> 		logger.debug(_("Loading configuration file %s") %
>> filename)
>> 
>> -		configs = ConfigParser.RawConfigParser()
>> +		configs = configparser.RawConfigParser()
>> 		configs.read([filename,])
>> 
>> 		# First apply all global configuration settings.
>> @@ -98,7 +101,7 @@
>> 				self.settings[k] = v
>> 
>> 		# Allow missing config section
>> -		except ConfigParser.NoSectionError:
>> +		except configparser.NoSectionError:
>> 			pass
>> 
>> 		for entry in configs.sections():
>> @@ -127,7 +130,7 @@
>> 			# Check if the provider is actually supported
>> and if there are
>> 			# some dependencies missing on this system.
>> 			if not provider.supported():
>> -				logger.warning("Provider '%s' is known,
>> but not supported on this machine" % (provider.name))
>> +				logger.warning("Provider '%s' is known,
>> but not supported on this machine" % provider.name)
>> 				continue
>> 
>> 			# Create an instance of the provider object
>> with settings from the
>> @@ -163,13 +166,13 @@
>> 		try:
>> 			entry(force=force)
>> 
>> -		except DDNSError, e:
>> -			logger.error(_("Dynamic DNS update for
>> %(hostname)s (%(provider)s) failed:") % \
>> -				{ "hostname" : entry.hostname,
>> "provider" : entry.name })
>> +		except DDNSError as e:
>> +			logger.error(_("Dynamic DNS update for
>> %(hostname)s (%(provider)s) failed:") %
>> +				{"hostname": entry.hostname,
>> "provider": entry.name})
>> 			logger.error("  %s: %s" %
>> (e.__class__.__name__, e.reason))
>> 			if e.message:
>> 				logger.error("  %s" % e.message)
>> 
>> -		except Exception, e:
>> -			logger.error(_("Dynamic DNS update for
>> %(hostname)s (%(provider)s) throwed an unhandled exception:") % \
>> -				{ "hostname" : entry.hostname,
>> "provider" : entry.name }, exc_info=True)
>> +		except Exception:
>> +			logger.error(_("Dynamic DNS update for
>> %(hostname)s (%(provider)s) threw an unhandled exception:") %
>> +						 {"hostname":
>> entry.hostname, "provider": entry.name}, exc_info=True)
>> Index: src/ddns/errors.py
>> IDEA additional info:
>> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
>> <+>UTF-8
>> ===================================================================
>> --- src/ddns/errors.py	(revision
>> c0277eeea2b2c1ed8f40f1248b28438e44e51912)
>> +++ src/ddns/errors.py	(date 1577472902317)
>> @@ -1,4 +1,4 @@
>> -#!/usr/bin/python
>> +#!/usr/bin/python3
>> ####################################################################
>> ###########
>> #                                                                  
>>          #
>> # ddns - A dynamic DNS client for IPFire                            
>>         #
>> @@ -21,6 +21,7 @@
>> 
>> N_ = lambda x: x
>> 
>> +
>> class DDNSError(Exception):
>> 	"""
>> 		Generic error class for all exceptions
>> 
>> 
>> Am 25.12.2019 um 16:52 schrieb Michael Tremer <
>> michael.tremer(a)ipfire.org>:
>> 
>> Hi,
>> 
>> Thanks for working on this.
>> 
>> There are some issues with this patch.
>> 
>> First of all, the formatting is off and all leading spaces have been
>> stripped.
>> 
>>> On 25 Dec 2019, at 16:39, Kim <kbarthel(a)ipfire.org> wrote:
>>> 
>>> ---
>>> .gitignore            |   1 +
>>> Makefile.am           |   2 +-
>>> configure.ac          |   6 +-
>>> ddns.in               |  30 ++-
>>> src/ddns/__init__.py  |  33 +--
>>> src/ddns/database.py  |   5 +-
>>> src/ddns/errors.py    |   5 +-
>>> src/ddns/i18n.py      |  11 +-
>>> src/ddns/providers.py | 545 +++++++++++++++++++++----------------
>>> -----
>>> src/ddns/system.py    |  44 ++--
>>> 10 files changed, 339 insertions(+), 343 deletions(-)
>>> 
>>> diff --git a/.gitignore b/.gitignore
>>> index cd5023c..df7e7eb 100644
>>> --- a/.gitignore
>>> +++ b/.gitignore
>>> @@ -27,3 +27,4 @@ intltool-extract.in
>>> intltool-merge.in
>>> intltool-update.in
>>> stamp-*
>>> +.idea
>> 
>> What does this have to do with the Python port?
>> 
>>> diff --git a/Makefile.am b/Makefile.am
>>> index fc119b8..d36f880 100644
>>> --- a/Makefile.am
>>> +++ b/Makefile.am
>>> @@ -1,7 +1,7 @@
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # Pakfire - The IPFire package management system
>>>                             #
>>> -# Copyright (C) 2013 Pakfire development team
>>>                                #
>>> +# Copyright (C) 2013-2019 Pakfire development team
>>>                           #
>> 
>> Pakfire?
>> 
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> diff --git a/configure.ac b/configure.ac
>>> index 14bccc0..320de10 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -1,7 +1,7 @@
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # Pakfire - The IPFire package management system
>>>                             #
>>> -# Copyright (C) 2013 Pakfire development team
>>>                                #
>>> +# Copyright (C) 2013-2019 Pakfire development team
>>>                           #
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> @@ -21,7 +21,7 @@
>>> AC_PREREQ([2.64])
>>> 
>>> AC_INIT([ddns],
>>> -	[012],
>>> +	[013],
>>> 	[info(a)ipfire.org],
>>> 	[ddns],
>>> 	[http://git.ipfire.org/?p=oddments/ddns.git;a=summary])
>> 
>> You do not need to tag a new release.
>> 
>>> @@ -54,7 +54,7 @@ AC_PROG_SED
>>> AC_PATH_PROG([XSLTPROC], [xsltproc])
>>> 
>>> # Python
>>> -AM_PATH_PYTHON([2.7])
>>> +AM_PATH_PYTHON([3])
>> 
>> Are you sure this will run with Python 3.0, 3.2, etc.?
>> 
>> I suppose it is safe to have 3.6 or even 3.8 here.
>> 
>>> save_LIBS="$LIBS"
>>> 
>>> diff --git a/ddns.in b/ddns.in
>>> index 1ca5f83..9bb267a 100644
>>> --- a/ddns.in
>>> +++ b/ddns.in
>>> @@ -1,8 +1,8 @@
>>> -#!/usr/bin/python
>>> +#!/usr/bin/python3
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # ddns - A dynamic DNS client for IPFire
>>>                                     #
>>> -# Copyright (C) 2012 IPFire development team
>>>                                 #
>>> +# Copyright (C) 2012-2019 IPFire development team
>>>                            #
>> 
>> See above.
>> 
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> @@ -27,38 +27,35 @@ from ddns.i18n import _
>>> 
>>> CONFIGURATION_FILE = "@configsdir@/ddns.conf"
>>> 
>>> +
>>> def main():
>>> 	# Parse command line
>>> 	p = argparse.ArgumentParser(description=_("Dynamic DNS
>>> Updater"))
>>> 
>>> -	p.add_argument("-d", "--debug", action="store_true",
>>> -		help=_("Enable debugging output"))
>>> +	p.add_argument("-d", "--debug", action="store_true",
>>> help=_("Enable debugging output"))
>>> 
>>> 	p.add_argument("-c", "--config", default=CONFIGURATION_FILE,
>>> -		help=_("Load configuration file (Default: %s)") %
>>> CONFIGURATION_FILE)
>>> +	               help=_("Load configuration file (Default: %s)")
>>> % CONFIGURATION_FILE)
>>> 
>>> 	# Create subparsers for commands.
>>> -	subparsers = p.add_subparsers(help=_("Sub-command help"),
>>> -		dest="subparsers_name")
>>> +	subparsers = p.add_subparsers(help=_("Sub-command help"),
>>> dest="subparsers_name")
>>> 
>>> 	# guess-ip-addresses
>>> -	p_guess_ip_addresses = subparsers.add_parser("guess-ip-
>>> addresses",
>>> -		help=_("Guess the external IP addresses"))
>>> +	p_guess_ip_addresses = subparsers.add_parser("guess-ip-
>>> addresses", help=_("Guess the external IP addresses"))
>>> 
>>> 	# list-providers
>>> -	p_list_providers = subparsers.add_parser("list-providers",
>>> -		help=_("List all available providers"))
>>> +	p_list_providers = subparsers.add_parser("list-providers",
>>> help=_("List all available providers"))
>>> 
>>> 	# update
>>> 	p_update = subparsers.add_parser("update", help=_("Update DNS
>>> record"))
>>> 	p_update.add_argument("hostname")
>>> 	p_update.add_argument("--force", action="store_true",
>>> -		help=_("Execute update even if the record is already up
>>> to date"))
>>> +	                      help=_("Execute update even if the record
>>> is already up to date"))
>> 
>> You have changed indentation here. Is there any need for it?
>> 
>> This doesn’t change the code, but further down, there is a lot of
>> noise in the patch and I do not know why.
>> 
>>> 	# update-all
>>> 	p_update_all = subparsers.add_parser("update-all",
>>> help=_("Update all DNS records"))
>>> 	p_update_all.add_argument("--force", action="store_true",
>>> -		help=_("Execute update even if the record is already up
>>> to date"))
>>> +	                          help=_("Execute update even if the
>>> record is already up to date"))
>>> 
>>> 	args = p.parse_args()
>>> 
>>> @@ -74,16 +71,16 @@ def main():
>>> 		# IPv6
>>> 		ipv6_address =
>>> d.system.guess_external_ip_address("ipv6")
>>> 		if ipv6_address:
>>> -			print _("IPv6 Address: %s") % ipv6_address
>>> +			print("IPv6 Address: %s" % ipv6_address)
>> 
>> You are removing the translation here.
>> 
>>> 		# IPv4
>>> 		ipv4_address =
>>> d.system.guess_external_ip_address("ipv4")
>>> 		if ipv4_address:
>>> -			print _("IPv4 Address: %s") % ipv4_address
>>> +			print("IPv4 Address: %s" % ipv4_address)
>> 
>> Likewise.
>> 
>>> 	elif args.subparsers_name == "list-providers":
>>> 		provider_names = d.get_provider_names()
>>> -		print "\n".join(provider_names)
>>> +		print("\n".join(provider_names))
>>> 
>>> 	elif args.subparsers_name == "update":
>>> 		d.updateone(hostname=args.hostname, force=args.force)
>>> @@ -94,4 +91,5 @@ def main():
>>> 	else:
>>> 		raise RuntimeError("Unhandled command: %s" %
>>> args.subparsers_name)
>>> 
>>> +
>> 
>> We only have one empty line after functions and two after classes.
>> 
>>> main()
>>> diff --git a/src/ddns/__init__.py b/src/ddns/__init__.py
>>> index 7f2729c..4fffcf7 100644
>>> --- a/src/ddns/__init__.py
>>> +++ b/src/ddns/__init__.py
>>> @@ -1,8 +1,8 @@
>>> -#!/usr/bin/python
>>> +#!/usr/bin/python3
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # ddns - A dynamic DNS client for IPFire
>>>                                     #
>>> -# Copyright (C) 2012 IPFire development team
>>>                                 #
>>> +# Copyright (C) 2012-2019 IPFire development team
>>>                            #
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> @@ -21,19 +21,20 @@
>>> 
>>> import logging
>>> import logging.handlers
>>> -import ConfigParser
>>> +import configparser
>>> 
>>> -from i18n import _
>>> +from .i18n import _
>>> 
>>> logger = logging.getLogger("ddns.core")
>>> logger.propagate = 1
>>> 
>>> -import database
>>> -import providers
>>> +from . import database
>>> +from . import providers
>>> 
>>> from .errors import *
>>> from .system import DDNSSystem
>>> 
>>> +
>> 
>> Another blank line.
>> 
>>> # Setup the logger.
>>> def setup_logging():
>>> 	rootlogger = logging.getLogger("ddns")
>>> @@ -51,8 +52,10 @@ def setup_logging():
>>> 	handler = logging.StreamHandler()
>>> 	rootlogger.addHandler(handler)
>>> 
>>> +
>>> setup_logging()
>> 
>> And here again.
>> 
>>> +
>> 
>> And again.
>> 
>>> class DDNSCore(object):
>>> 	def __init__(self, debug=False):
>>> 		# In debug mode, enable debug logging.
>>> @@ -89,7 +92,7 @@ class DDNSCore(object):
>>> 	def load_configuration(self, filename):
>>> 		logger.debug(_("Loading configuration file %s") %
>>> filename)
>>> 
>>> -		configs = ConfigParser.RawConfigParser()
>>> +		configs = configparser.RawConfigParser()
>>> 		configs.read([filename,])
>>> 
>>> 		# First apply all global configuration settings.
>>> @@ -98,7 +101,7 @@ class DDNSCore(object):
>>> 				self.settings[k] = v
>>> 
>>> 		# Allow missing config section
>>> -		except ConfigParser.NoSectionError:
>>> +		except configparser.NoSectionError:
>>> 			pass
>>> 
>>> 		for entry in configs.sections():
>>> @@ -127,7 +130,7 @@ class DDNSCore(object):
>>> 			# Check if the provider is actually supported
>>> and if there are
>>> 			# some dependencies missing on this system.
>>> 			if not provider.supported():
>>> -				logger.warning("Provider '%s' is known,
>>> but not supported on this machine" % (provider.name))
>>> +				logger.warning("Provider '%s' is known,
>>> but not supported on this machine" % provider.name)
>>> 				continue
>>> 
>>> 			# Create an instance of the provider object
>>> with settings from the
>>> @@ -163,13 +166,13 @@ class DDNSCore(object):
>>> 		try:
>>> 			entry(force=force)
>>> 
>>> -		except DDNSError, e:
>>> -			logger.error(_("Dynamic DNS update for
>>> %(hostname)s (%(provider)s) failed:") % \
>>> -				{ "hostname" : entry.hostname,
>>> "provider" : entry.name })
>>> +		except DDNSError as e:
>>> +			logger.error(_("Dynamic DNS update for
>>> %(hostname)s (%(provider)s) failed:") %
>>> +				{"hostname": entry.hostname,
>>> "provider": entry.name})
>> 
>> You are removing spaces here for no reason.
>> 
>>> 			logger.error("  %s: %s" %
>>> (e.__class__.__name__, e.reason))
>>> 			if e.message:
>>> 				logger.error("  %s" % e.message)
>>> 
>>> -		except Exception, e:
>>> -			logger.error(_("Dynamic DNS update for
>>> %(hostname)s (%(provider)s) throwed an unhandled exception:") % \
>>> -				{ "hostname" : entry.hostname,
>>> "provider" : entry.name }, exc_info=True)
>>> +		except Exception:
>>> +			logger.error(_("Dynamic DNS update for
>>> %(hostname)s (%(provider)s) threw an unhandled exception:") %
>>> +						 {"hostname":
>>> entry.hostname, "provider": entry.name}, exc_info=True)
>> 
>> See above.
>> 
>>> diff --git a/src/ddns/database.py b/src/ddns/database.py
>>> index 70a7363..45c445f 100644
>>> --- a/src/ddns/database.py
>>> +++ b/src/ddns/database.py
>>> @@ -1,8 +1,8 @@
>>> -#!/usr/bin/python
>>> +#!/usr/bin/python3
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # ddns - A dynamic DNS client for IPFire
>>>                                     #
>>> -# Copyright (C) 2014 IPFire development team
>>>                                 #
>>> +# Copyright (C) 2012-2019 IPFire development team
>>>                            #
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> @@ -82,6 +82,7 @@ class DDNSDatabase(object):
>>> 
>>> 	def _close_database(self):
>>> 		if self._db:
>>> +			# TODO: Check Unresolved attribute reference
>>> '_db_close' for class 'DDNSDatabase'
>>> 			self._db_close()
>>> 			self._db = None
>> 
>> What does this mean?
>> 
>> Does that mean this patch isn’t ready for production?
>> 
>>> diff --git a/src/ddns/errors.py b/src/ddns/errors.py
>>> index a8a2017..128d20d 100644
>>> --- a/src/ddns/errors.py
>>> +++ b/src/ddns/errors.py
>>> @@ -1,8 +1,8 @@
>>> -#!/usr/bin/python
>>> +#!/usr/bin/python3
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # ddns - A dynamic DNS client for IPFire
>>>                                     #
>>> -# Copyright (C) 2012-2017 IPFire development team
>>>                            #
>>> +# Copyright (C) 2012-2019 IPFire development team
>>>                            #
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> @@ -21,6 +21,7 @@
>>> 
>>> N_ = lambda x: x
>>> 
>>> +
>> 
>> Blank line again.
>> 
>>> class DDNSError(Exception):
>>> 	"""
>>> 		Generic error class for all exceptions
>>> diff --git a/src/ddns/i18n.py b/src/ddns/i18n.py
>>> index 170414d..b71f7dc 100644
>>> --- a/src/ddns/i18n.py
>>> +++ b/src/ddns/i18n.py
>>> @@ -1,8 +1,8 @@
>>> -#!/usr/bin/python
>>> +#!/usr/bin/python3
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # ddns - A dynamic DNS client for IPFire
>>>                                     #
>>> -# Copyright (C) 2012 IPFire development team
>>>                                 #
>>> +# Copyright (C) 2012-2019 IPFire development team
>>>                            #
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> @@ -25,15 +25,14 @@ TEXTDOMAIN = "ddns"
>>> 
>>> N_ = lambda x: x
>>> 
>>> +
>> 
>> Blank line.
>> 
>>> def _(singular, plural=None, n=None):
>>> 	"""
>>> 		A function that returnes the translation of a string if
>>> available.
>>> -
>>> 		The language is taken from the system environment.
>>> -        """
>>> -	if not plural is None:
>>> +	"""
>>> +	if plural is not None:
>>> 		assert n is not None
>>> 		return gettext.dngettext(TEXTDOMAIN, singular, plural,
>>> n)
>>> 
>>> 	return gettext.dgettext(TEXTDOMAIN, singular)
>>> -
>>> diff --git a/src/ddns/providers.py b/src/ddns/providers.py
>>> index 661fbcc..b4a27a1 100644
>>> --- a/src/ddns/providers.py
>>> +++ b/src/ddns/providers.py
>>> @@ -1,8 +1,8 @@
>>> -#!/usr/bin/python
>>> +#!/usr/bin/python3
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # ddns - A dynamic DNS client for IPFire
>>>                                     #
>>> -# Copyright (C) 2012-2017 IPFire development team
>>>                            #
>>> +# Copyright (C) 2012-2019 IPFire development team
>>>                            #
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> @@ -23,10 +23,10 @@ import datetime
>>> import logging
>>> import os
>>> import subprocess
>>> -import urllib2
>>> +import urllib.request, urllib.error, urllib.parse
>>> import xml.dom.minidom
>>> 
>>> -from i18n import _
>>> +from .i18n import _
>>> 
>>> # Import all possible exception types.
>>> from .errors import *
>>> @@ -36,12 +36,14 @@ logger.propagate = 1
>>> 
>>> _providers = {}
>>> 
>>> +
>> 
>> I will stop commenting on the blank lines now, but there is many many
>> more.
>> 
>>> def get():
>>> 	"""
>>> 		Returns a dict with all automatically registered
>>> providers.
>>> 	"""
>>> 	return _providers.copy()
>>> 
>>> +
>>> class DDNSProvider(object):
>>> 	# A short string that uniquely identifies
>>> 	# this provider.
>>> @@ -84,7 +86,7 @@ class DDNSProvider(object):
>>> 			if not all((provider.handle, provider.name,
>>> provider.website)):
>>> 				raise DDNSError(_("Provider is not
>>> properly configured"))
>>> 
>>> -			assert not _providers.has_key(provider.handle),
>>> \
>>> +			assert provider.handle not in _providers, \
>>> 				"Provider '%s' has already been
>>> registered" % provider.handle
>>> 
>>> 			_providers[provider.handle] = provider
>>> @@ -109,7 +111,7 @@ class DDNSProvider(object):
>>> 		return "<DDNS Provider %s (%s)>" % (self.name,
>>> self.handle)
>>> 
>>> 	def __cmp__(self, other):
>>> -		return cmp(self.hostname, other.hostname)
>>> +		return (lambda a, b: (a > b)-(a < b))(self.hostname,
>>> other.hostname)
>> 
>> __cmp__ should be replaced by __eq__ and __lt__ at least.
>> 
>> Those are straight forward comparisons of the hostname, and this
>> lambda function is confusing and difficult to read.
>> 
>>> 	@property
>>> 	def db(self):
>>> @@ -176,8 +178,8 @@ class DDNSProvider(object):
>>> 			self.core.db.log_failure(self.hostname, e)
>>> 			raise
>>> 
>>> -		logger.info(_("Dynamic DNS update for %(hostname)s
>>> (%(provider)s) successful") % \
>>> -			{ "hostname" : self.hostname, "provider" :
>>> self.name })
>>> +		logger.info(_("Dynamic DNS update for %(hostname)s
>>> (%(provider)s) successful") %
>>> +		            {"hostname": self.hostname, "provider":
>>> self.name})
>> 
>> Spaces.
>> 
>>> 		self.core.db.log_success(self.hostname)
>>> 
>>> 	def update(self):
>>> @@ -192,7 +194,7 @@ class DDNSProvider(object):
>>> 
>>> 	def remove_protocol(self, proto):
>>> 		if not self.can_remove_records:
>>> -			raise RuntimeError, "can_remove_records is
>>> enabled, but remove_protocol() not implemented"
>>> +			raise RuntimeError("can_remove_records is
>>> enabled, but remove_protocol() not implemented")
>>> 
>>> 		raise NotImplementedError
>>> 
>>> @@ -201,22 +203,22 @@ class DDNSProvider(object):
>>> 		# If the IP addresses have changed, an update is
>>> required
>>> 		if self.ip_address_changed(self.protocols):
>>> 			logger.debug(_("An update for %(hostname)s
>>> (%(provider)s)"
>>> -				" is performed because of an IP address
>>> change") % \
>>> -				{ "hostname" : self.hostname,
>>> "provider" : self.name })
>>> +			               " is performed because of an IP
>>> address change") %
>>> +			             {"hostname": self.hostname,
>>> "provider": self.name})
>>> 
>> 
>> Spaces.
>> 
>>> 			return True
>>> 
>>> 		# If the holdoff time has expired, an update is
>>> required, too
>>> 		if self.holdoff_time_expired():
>>> 			logger.debug(_("An update for %(hostname)s
>>> (%(provider)s)"
>>> -				" is performed because the holdoff time
>>> has expired") % \
>>> -				{ "hostname" : self.hostname,
>>> "provider" : self.name })
>>> +			               " is performed because the
>>> holdoff time has expired") %
>>> +			             {"hostname": self.hostname,
>>> "provider": self.name})
>>> 
>> 
>> Likewise.
>> 
>>> 			return True
>>> 
>>> 		# Otherwise, we don't need to perform an update
>>> -		logger.debug(_("No update required for %(hostname)s
>>> (%(provider)s)") % \
>>> -			{ "hostname" : self.hostname, "provider" :
>>> self.name })
>>> +		logger.debug(_("No update required for %(hostname)s
>>> (%(provider)s)") %
>>> +		             {"hostname": self.hostname, "provider":
>>> self.name})
>> 
>> Likewise.
>> 
>>> 		return False
>>> 
>>> @@ -234,8 +236,7 @@ class DDNSProvider(object):
>>> 
>>> 		# If there is no holdoff time, we won't update ever
>>> again.
>>> 		if self.holdoff_failure_days is None:
>>> -			logger.warning(_("An update has not been
>>> performed because earlier updates failed for %s") \
>>> -				% self.hostname)
>>> +			logger.warning(_("An update has not been
>>> performed because earlier updates failed for %s") % self.hostname)
>>> 			logger.warning(_("There will be no retries"))
>> 
>> There is a limit to the length of a line. It should be 80 characters
>> and in difficult cases can be 120 characters.
>> 
>> This has been tried here before, but your patch removes it. Why?
>> 
>>> 			return True
>>> @@ -248,8 +249,7 @@ class DDNSProvider(object):
>>> 		if now < holdoff_end:
>>> 			failure_message =
>>> self.db.last_update_failure_message(self.hostname)
>>> 
>>> -			logger.warning(_("An update has not been
>>> performed because earlier updates failed for %s") \
>>> -				% self.hostname)
>>> +			logger.warning(_("An update has not been
>>> performed because earlier updates failed for %s") % self.hostname)
>> 
>> Likewise.
>> 
>>> 			if failure_message:
>>> 				logger.warning(_("Last failure
>>> message:"))
>>> @@ -315,8 +315,8 @@ class DDNSProvider(object):
>>> 			logger.debug("The holdoff time has expired for
>>> %s" % self.hostname)
>>> 			return True
>>> 		else:
>>> -			logger.debug("Updates for %s are held off until
>>> %s" % \
>>> -				(self.hostname, holdoff_end))
>>> +			logger.debug("Updates for %s are held off until
>>> %s" %
>>> +			             (self.hostname, holdoff_end))
>>> 			return False
>>> 
>>> 	def send_request(self, *args, **kwargs):
>>> @@ -362,8 +362,8 @@ class DDNSProtocolDynDNS2(object):
>>> 
>>> 	def prepare_request_data(self, proto):
>>> 		data = {
>>> -			"hostname" : self.hostname,
>>> -			"myip"     : self.get_address(proto),
>>> +			"hostname": self.hostname,
>>> +			"myip": self.get_address(proto),
>>> 		}
>> 
>> Why are those spaces removed here?
>> 
>> They make the patch very long and they actually do not change
>> anything.
>> 
>>> 		return data
>>> @@ -375,8 +375,7 @@ class DDNSProtocolDynDNS2(object):
>>> 
>>> 	def send_request(self, data):
>>> 		# Send update to the server.
>>> -		response = DDNSProvider.send_request(self, self.url,
>>> data=data,
>>> -			username=self.username, password=self.password)
>>> +		response = DDNSProvider.send_request(self, self.url,
>>> data=data, username=self.username, password=self.password)
>> 
>> Again, a line that got "unwrapped".
>> 
>>> 		# Get the full response message.
>>> 		output = response.read()
>>> @@ -413,7 +412,7 @@ class DDNSResponseParserXML(object):
>>> 		will be sent by various providers. This class uses the
>>> python
>>> 		shipped XML minidom module to walk through the XML tree
>>> and return
>>> 		a requested element.
>>> -        """
>>> +	"""
>> 
>> This is allowed, because Python 3 will complain about the spaces.
>> 
>>> 	def get_xml_tag_value(self, document, content):
>>> 		# Send input to the parser.
>>> @@ -437,9 +436,9 @@ class DDNSResponseParserXML(object):
>>> 
>>> 
>>> class DDNSProviderAllInkl(DDNSProvider):
>>> -	handle    = "all-inkl.com"
>>> -	name      = "All-inkl.com"
>>> -	website   = "http://all-inkl.com/"
>>> +	handle = "all-inkl.com"
>>> +	name = "All-inkl.com"
>>> +	website = "http://all-inkl.com/"
>>> 	protocols = ("ipv4",)
>> 
>> Spaces removed. Why? See above. And below...
>> 
>>> 	# There are only information provided by the vendor how to
>>> @@ -467,8 +466,8 @@ class DDNSProviderAllInkl(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderBindNsupdate(DDNSProvider):
>>> -	handle  = "nsupdate"
>>> -	name    = "BIND nsupdate utility"
>>> +	handle = "nsupdate"
>>> +	name = "BIND nsupdate utility"
>>> 	website = "http://en.wikipedia.org/wiki/Nsupdate"
>>> 
>>> 	DEFAULT_TTL = 60
>>> @@ -494,9 +493,7 @@ class DDNSProviderBindNsupdate(DDNSProvider):
>>> 		# -t sets the timeout
>>> 		command = ["nsupdate", "-v", "-t", "60"]
>>> 
>>> -		p = subprocess.Popen(command, shell=True,
>>> -			stdin=subprocess.PIPE, stdout=subprocess.PIPE,
>>> stderr=subprocess.PIPE,
>>> -		)
>>> +		p = subprocess.Popen(command, shell=True,
>>> stdin=subprocess.PIPE, stdout=subprocess.PIPE,
>>> stderr=subprocess.PIPE)
>>> 		stdout, stderr = p.communicate(scriptlet)
>> 
>> More unwrapped lines.
>> 
>>> 		if p.returncode == 0:
>>> @@ -533,7 +530,7 @@ class DDNSProviderBindNsupdate(DDNSProvider):
>>> 
>>> 			scriptlet.append("update delete %s. %s" %
>>> (self.hostname, rrtype))
>>> 			scriptlet.append("update add %s. %s %s %s" % \
>>> -				(self.hostname, ttl, rrtype, address))
>>> +			                 (self.hostname, ttl, rrtype,
>>> address))
>>> 
>>> 		# Send the actions to the server.
>>> 		scriptlet.append("send")
>>> @@ -551,9 +548,9 @@ class DDNSProviderBindNsupdate(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderChangeIP(DDNSProvider):
>>> -	handle    = "changeip.com"
>>> -	name      = "ChangeIP.com"
>>> -	website   = "https://changeip.com"
>>> +	handle = "changeip.com"
>>> +	name = "ChangeIP.com"
>>> +	website = "https://changeip.com"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Detailed information about the update api can be found here.
>>> @@ -564,17 +561,16 @@ class DDNSProviderChangeIP(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"hostname" : self.hostname,
>>> -			"myip"     : self.get_address(proto),
>>> +			"hostname": self.hostname,
>>> +			"myip": self.get_address(proto),
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> 		try:
>>> -			response = self.send_request(self.url,
>>> username=self.username, password=self.password,
>>> -				data=data)
>>> +			response = self.send_request(self.url,
>>> username=self.username, password=self.password, data=data)
>>> 
>>> 		# Handle error codes.
>>> -		except urllib2.HTTPError, e:
>>> +		except urllib.error.HTTPError as e:
>>> 			if e.code == 422:
>>> 				raise DDNSRequestError(_("Domain not
>>> found."))
>>> 
>>> @@ -585,13 +581,13 @@ class DDNSProviderChangeIP(DDNSProvider):
>>> 			return
>>> 
>>> 		# If we got here, some other update error happened.
>>> -		raise DDNSUpdateError(_("Server response: %s") %
>>> output)
>>> +		raise DDNSUpdateError(_("Server response: %s") %
>>> response)
>>> 
>>> 
>>> class DDNSProviderDesecIO(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "desec.io"
>>> -	name      = "desec.io"
>>> -	website   = "https://www.desec.io"
>>> +	handle = "desec.io"
>>> +	name = "desec.io"
>>> +	website = "https://www.desec.io"
>>> 	protocols = ("ipv6", "ipv4",)
>>> 
>>> 	# ipv4 / ipv6 records are automatically removed when the update
>>> @@ -616,9 +612,9 @@ class DDNSProviderDesecIO(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDDNSS(DDNSProvider):
>>> -	handle    = "ddnss.de"
>>> -	name      = "DDNSS"
>>> -	website   = "http://www.ddnss.de"
>>> +	handle = "ddnss.de"
>>> +	name = "DDNSS"
>>> +	website = "http://www.ddnss.de"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Detailed information about how to send the update request and
>>> possible response
>>> @@ -631,8 +627,8 @@ class DDNSProviderDDNSS(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"ip"   : self.get_address(proto),
>>> -			"host" : self.hostname,
>>> +			"ip": self.get_address(proto),
>>> +			"host": self.hostname,
>>> 		}
>>> 
>>> 		# Check if a token has been set.
>>> @@ -642,8 +638,8 @@ class DDNSProviderDDNSS(DDNSProvider):
>>> 		# Check if username and hostname are given.
>>> 		elif self.username and self.password:
>>> 			data.update({
>>> -				"user" : self.username,
>>> -				"pwd"  : self.password,
>>> +				"user": self.username,
>>> +				"pwd": self.password,
>>> 			})
>>> 
>>> 		# Raise an error if no auth details are given.
>>> @@ -682,9 +678,9 @@ class DDNSProviderDDNSS(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDHS(DDNSProvider):
>>> -	handle    = "dhs.org"
>>> -	name      = "DHS International"
>>> -	website   = "http://dhs.org/"
>>> +	handle = "dhs.org"
>>> +	name = "DHS International"
>>> +	website = "http://dhs.org/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# No information about the used update api provided on webpage,
>>> @@ -695,16 +691,15 @@ class DDNSProviderDHS(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"domain"       : self.hostname,
>>> -			"ip"           : self.get_address(proto),
>>> -			"hostcmd"      : "edit",
>>> -			"hostcmdstage" : "2",
>>> -			"type"         : "4",
>>> +			"domain": self.hostname,
>>> +			"ip": self.get_address(proto),
>>> +			"hostcmd": "edit",
>>> +			"hostcmdstage": "2",
>>> +			"type": "4",
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> -		response = self.send_request(self.url,
>>> username=self.username, password=self.password,
>>> -			data=data)
>>> +		response = self.send_request(self.url,
>>> username=self.username, password=self.password, data=data)
>>> 
>>> 		# Handle success messages.
>>> 		if response.code == 200:
>>> @@ -715,9 +710,9 @@ class DDNSProviderDHS(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDNSpark(DDNSProvider):
>>> -	handle    = "dnspark.com"
>>> -	name      = "DNS Park"
>>> -	website   = "http://dnspark.com/"
>>> +	handle = "dnspark.com"
>>> +	name = "DNS Park"
>>> +	website = "http://dnspark.com/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Informations to the used api can be found here:
>>> @@ -728,13 +723,12 @@ class DDNSProviderDNSpark(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"domain" : self.hostname,
>>> -			"ip"     : self.get_address(proto),
>>> +			"domain": self.hostname,
>>> +			"ip": self.get_address(proto),
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> -		response = self.send_request(self.url,
>>> username=self.username, password=self.password,
>>> -			data=data)
>>> +		response = self.send_request(self.url,
>>> username=self.username, password=self.password, data=data)
>>> 
>>> 		# Get the full response message.
>>> 		output = response.read()
>>> @@ -764,9 +758,9 @@ class DDNSProviderDNSpark(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDtDNS(DDNSProvider):
>>> -	handle    = "dtdns.com"
>>> -	name      = "DtDNS"
>>> -	website   = "http://dtdns.com/"
>>> +	handle = "dtdns.com"
>>> +	name = "DtDNS"
>>> +	website = "http://dtdns.com/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the HTTPS request is to be
>>> found
>>> @@ -777,9 +771,9 @@ class DDNSProviderDtDNS(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"ip" : self.get_address(proto),
>>> -			"id" : self.hostname,
>>> -			"pw" : self.password
>>> +			"ip": self.get_address(proto),
>>> +			"id": self.hostname,
>>> +			"pw": self.password
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> @@ -819,9 +813,9 @@ class DDNSProviderDtDNS(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDuckDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "duckdns.org"
>>> -	name      = "Duck DNS"
>>> -	website   = "http://www.duckdns.org/"
>>> +	handle = "duckdns.org"
>>> +	name = "Duck DNS"
>>> +	website = "http://www.duckdns.org/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the request is to be found
>>> @@ -831,9 +825,9 @@ class DDNSProviderDuckDNS(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDyFi(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "dy.fi"
>>> -	name      = "dy.fi"
>>> -	website   = "https://www.dy.fi/"
>>> +	handle = "dy.fi"
>>> +	name = "dy.fi"
>>> +	website = "https://www.dy.fi/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the request is to be found
>>> @@ -849,9 +843,9 @@ class DDNSProviderDyFi(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDynDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "dyndns.org"
>>> -	name      = "Dyn"
>>> -	website   = "http://dyn.com/dns/"
>>> +	handle = "dyndns.org"
>>> +	name = "Dyn"
>>> +	website = "http://dyn.com/dns/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the request is to be found
>>> @@ -862,9 +856,9 @@ class DDNSProviderDynDNS(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDomainOffensive(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> -	handle    = "do.de"
>>> -	name      = "Domain-Offensive"
>>> -	website   = "https://www.do.de/"
>>> +	handle = "do.de"
>>> +	name = "Domain-Offensive"
>>> +	website = "https://www.do.de/"
>>> 	protocols = ("ipv6", "ipv4")
>>> 
>>> 	# Detailed information about the request and response codes
>>> @@ -873,10 +867,11 @@ class
>>> DDNSProviderDomainOffensive(DDNSProtocolDynDNS2, DDNSProvider):
>>> 
>>> 	url = "https://ddns.do.de/"
>>> 
>>> +
>>> class DDNSProviderDynUp(DDNSProvider):
>>> -	handle    = "dynup.de"
>>> -	name      = "DynUp.DE"
>>> -	website   = "http://dynup.de/"
>>> +	handle = "dynup.de"
>>> +	name = "DynUp.DE"
>>> +	website = "http://dynup.de/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the HTTPS request is to be
>>> found
>>> @@ -887,10 +882,10 @@ class DDNSProviderDynUp(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"username" : self.username,
>>> -			"password" : self.password,
>>> -			"hostname" : self.hostname,
>>> -			"print" : '1',
>>> +			"username": self.username,
>>> +			"password": self.password,
>>> +			"hostname": self.hostname,
>>> +			"print": '1',
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> @@ -903,18 +898,17 @@ class DDNSProviderDynUp(DDNSProvider):
>>> 		output = output.strip()
>>> 
>>> 		# Handle success messages.
>>> -		if output.startswith("I:OK") :
>>> +		if output.startswith("I:OK"):
>>> 			return
>>> 
>>> 		# If we got here, some other update error happened.
>>> 		raise DDNSUpdateError
>>> 
>>> 
>>> -
>>> class DDNSProviderDynU(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "dynu.com"
>>> -	name      = "Dynu"
>>> -	website   = "http://dynu.com/"
>>> +	handle = "dynu.com"
>>> +	name = "Dynu"
>>> +	website = "http://dynu.com/"
>>> 	protocols = ("ipv6", "ipv4",)
>>> 
>>> 	# Detailed information about the request and response codes
>>> @@ -939,9 +933,9 @@ class DDNSProviderDynU(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderEasyDNS(DDNSProvider):
>>> -	handle    = "easydns.com"
>>> -	name      = "EasyDNS"
>>> -	website   = "http://www.easydns.com/"
>>> +	handle = "easydns.com"
>>> +	name = "EasyDNS"
>>> +	website = "http://www.easydns.com/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Detailed information about the request and response codes
>>> @@ -952,13 +946,12 @@ class DDNSProviderEasyDNS(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"myip"     : self.get_address(proto, "-"),
>>> -			"hostname" : self.hostname,
>>> +			"myip": self.get_address(proto, "-"),
>>> +			"hostname": self.hostname,
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> -		response = self.send_request(self.url, data=data,
>>> -			username=self.username, password=self.password)
>>> +		response = self.send_request(self.url, data=data,
>>> username=self.username, password=self.password)
>>> 
>>> 		# Get the full response message.
>>> 		output = response.read()
>>> @@ -988,9 +981,9 @@ class DDNSProviderEasyDNS(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDomopoli(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "domopoli.de"
>>> -	name      = "domopoli.de"
>>> -	website   = "http://domopoli.de/"
>>> +	handle = "domopoli.de"
>>> +	name = "domopoli.de"
>>> +	website = "http://domopoli.de/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# https://www.domopoli.de/?page=howto#DynDns_start
>>> @@ -999,9 +992,9 @@ class DDNSProviderDomopoli(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDynsNet(DDNSProvider):
>>> -	handle    = "dyns.net"
>>> -	name      = "DyNS"
>>> -	website   = "http://www.dyns.net/"
>>> +	handle = "dyns.net"
>>> +	name = "DyNS"
>>> +	website = "http://www.dyns.net/"
>>> 	protocols = ("ipv4",)
>>> 	can_remove_records = False
>>> 
>>> @@ -1013,10 +1006,10 @@ class DDNSProviderDynsNet(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"ip"       : self.get_address(proto),
>>> -			"host"     : self.hostname,
>>> -			"username" : self.username,
>>> -			"password" : self.password,
>>> +			"ip": self.get_address(proto),
>>> +			"host": self.hostname,
>>> +			"username": self.username,
>>> +			"password": self.password,
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> @@ -1044,9 +1037,9 @@ class DDNSProviderDynsNet(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderEnomCom(DDNSResponseParserXML, DDNSProvider):
>>> -	handle    = "enom.com"
>>> -	name      = "eNom Inc."
>>> -	website   = "http://www.enom.com/"
>>> +	handle = "enom.com"
>>> +	name = "eNom Inc."
>>> +	website = "http://www.enom.com/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# There are very detailed information about how to send an
>>> update request and
>>> @@ -1058,11 +1051,11 @@ class
>>> DDNSProviderEnomCom(DDNSResponseParserXML, DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"command"        : "setdnshost",
>>> -			"responsetype"   : "xml",
>>> -			"address"        : self.get_address(proto),
>>> -			"domainpassword" : self.password,
>>> -			"zone"           : self.hostname
>>> +			"command": "setdnshost",
>>> +			"responsetype": "xml",
>>> +			"address": self.get_address(proto),
>>> +			"domainpassword": self.password,
>>> +			"zone": self.hostname
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> @@ -1088,9 +1081,9 @@ class
>>> DDNSProviderEnomCom(DDNSResponseParserXML, DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderEntryDNS(DDNSProvider):
>>> -	handle    = "entrydns.net"
>>> -	name      = "EntryDNS"
>>> -	website   = "http://entrydns.net/"
>>> +	handle = "entrydns.net"
>>> +	name = "EntryDNS"
>>> +	website = "http://entrydns.net/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Some very tiny details about their so called "Simple API" can
>>> be found
>>> @@ -1100,7 +1093,7 @@ class DDNSProviderEntryDNS(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"ip" : self.get_address(proto),
>>> +			"ip": self.get_address(proto),
>>> 		}
>>> 
>>> 		# Add auth token to the update url.
>>> @@ -1111,7 +1104,7 @@ class DDNSProviderEntryDNS(DDNSProvider):
>>> 			response = self.send_request(url, data=data)
>>> 
>>> 		# Handle error codes
>>> -		except urllib2.HTTPError, e:
>>> +		except urllib.error.HTTPError as e:
>>> 			if e.code == 404:
>>> 				raise DDNSAuthenticationError
>>> 
>>> @@ -1129,9 +1122,9 @@ class DDNSProviderEntryDNS(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderFreeDNSAfraidOrg(DDNSProvider):
>>> -	handle    = "freedns.afraid.org"
>>> -	name      = "freedns.afraid.org"
>>> -	website   = "http://freedns.afraid.org/"
>>> +	handle = "freedns.afraid.org"
>>> +	name = "freedns.afraid.org"
>>> +	website = "http://freedns.afraid.org/"
>>> 
>>> 	# No information about the request or response could be found
>>> on the vendor
>>> 	# page. All used values have been collected by testing.
>>> @@ -1140,7 +1133,7 @@ class
>>> DDNSProviderFreeDNSAfraidOrg(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"address" : self.get_address(proto),
>>> +			"address": self.get_address(proto),
>>> 		}
>>> 
>>> 		# Add auth token to the update url.
>>> @@ -1167,59 +1160,59 @@ class
>>> DDNSProviderFreeDNSAfraidOrg(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderItsdns(DDNSProtocolDynDNS2, DDNSProvider):
>>> -		handle    = "inwx.com"
>>> -		name      = "INWX"
>>> -		website   = "https://www.inwx.com"
>>> -		protocols = ("ipv6", "ipv4")
>>> +	handle = "inwx.com"
>>> +	name = "INWX"
>>> +	website = "https://www.inwx.com"
>>> +	protocols = ("ipv6", "ipv4")
>>> 
>>> -		# Information about the format of the HTTP request is
>>> to be found
>>> -		# here: https://www.inwx.com/en/nameserver2/dyndns
>>> (requires login)
>>> -		# Notice: The URL is the same for: inwx.com|de|at|ch|es
>>> +	# Information about the format of the HTTP request is to be
>>> found
>>> +	# here: https://www.inwx.com/en/nameserver2/dyndns (requires
>>> login)
>>> +	# Notice: The URL is the same for: inwx.com|de|at|ch|es
>>> 
>>> -		url = "https://dyndns.inwx.com/nic/update"
>>> +	url = "https://dyndns.inwx.com/nic/update"
>>> 
>>> 
>>> class DDNSProviderItsdns(DDNSProtocolDynDNS2, DDNSProvider):
>>> -		handle    = "itsdns.de"
>>> -		name      = "it's DNS"
>>> -		website   = "http://www.itsdns.de/"
>>> -		protocols = ("ipv6", "ipv4")
>>> +	handle = "itsdns.de"
>>> +	name = "it's DNS"
>>> +	website = "http://www.itsdns.de/"
>>> +	protocols = ("ipv6", "ipv4")
>>> 
>>> -		# Information about the format of the HTTP request is
>>> to be found
>>> -		# here: https://www.itsdns.de/dynupdatehelp.htm
>>> +	# Information about the format of the HTTP request is to be
>>> found
>>> +	# here: https://www.itsdns.de/dynupdatehelp.htm
>>> 
>>> -		url = "https://www.itsdns.de/update.php"
>>> +	url = "https://www.itsdns.de/update.php"
>>> 
>>> 
>>> class DDNSProviderJoker(DDNSProtocolDynDNS2, DDNSProvider):
>>> -		handle  = "joker.com"
>>> -		name    = "Joker.com Dynamic DNS"
>>> -		website = "https://joker.com/"
>>> -		protocols = ("ipv4",)
>>> +	handle = "joker.com"
>>> +	name = "Joker.com Dynamic DNS"
>>> +	website = "https://joker.com/"
>>> +	protocols = ("ipv4",)
>>> 
>>> -		# Information about the request can be found here:
>>> -		# 
>>> https://joker.com/faq/content/11/427/en/what-is-dynamic-dns-dyndns.html
>>> -		# Using DynDNS V2 protocol over HTTPS here
>>> +	# Information about the request can be found here:
>>> +	# 
>>> https://joker.com/faq/content/11/427/en/what-is-dynamic-dns-dyndns.html
>>> +	# Using DynDNS V2 protocol over HTTPS here
>>> 
>>> -		url = "https://svc.joker.com/nic/update"
>>> +	url = "https://svc.joker.com/nic/update"
>>> 
>>> 
>>> class DDNSProviderGoogle(DDNSProtocolDynDNS2, DDNSProvider):
>>> -        handle    = "domains.google.com"
>>> -        name      = "Google Domains"
>>> -        website   = "https://domains.google.com/"
>>> -        protocols = ("ipv4",)
>>> +	handle = "domains.google.com"
>>> +	name = "Google Domains"
>>> +	website = "https://domains.google.com/"
>>> +	protocols = ("ipv4",)
>>> 
>>> -        # Information about the format of the HTTP request is to
>>> be found
>>> -        # here: 
>>> https://support.google.com/domains/answer/6147083?hl=en
>>> +	# Information about the format of the HTTP request is to be
>>> found
>>> +	# here: https://support.google.com/domains/answer/6147083?hl=en
>>> 
>>> -        url = "https://domains.google.com/nic/update"
>>> +	url = "https://domains.google.com/nic/update"
>>> 
>>> 
>>> class DDNSProviderLightningWireLabs(DDNSProvider):
>>> -	handle    = "dns.lightningwirelabs.com"
>>> -	name      = "Lightning Wire Labs DNS Service"
>>> -	website   = "http://dns.lightningwirelabs.com/"
>>> +	handle = "dns.lightningwirelabs.com"
>>> +	name = "Lightning Wire Labs DNS Service"
>>> +	website = "http://dns.lightningwirelabs.com/"
>>> 
>>> 	# Information about the format of the HTTPS request is to be
>>> found
>>> 	# https://dns.lightningwirelabs.com/knowledge-base/api/ddns
>>> @@ -1227,10 +1220,10 @@ class
>>> DDNSProviderLightningWireLabs(DDNSProvider):
>>> 	url = "https://dns.lightningwirelabs.com/update"
>>> 
>>> 	def update(self):
>>> -		data =  {
>>> -			"hostname" : self.hostname,
>>> -			"address6" : self.get_address("ipv6", "-"),
>>> -			"address4" : self.get_address("ipv4", "-"),
>>> +		data = {
>>> +			"hostname": self.hostname,
>>> +			"address6": self.get_address("ipv6", "-"),
>>> +			"address4": self.get_address("ipv4", "-"),
>>> 		}
>>> 
>>> 		# Check if a token has been set.
>>> @@ -1240,8 +1233,8 @@ class
>>> DDNSProviderLightningWireLabs(DDNSProvider):
>>> 		# Check for username and password.
>>> 		elif self.username and self.password:
>>> 			data.update({
>>> -				"username" : self.username,
>>> -				"password" : self.password,
>>> +				"username": self.username,
>>> +				"password": self.password,
>>> 			})
>>> 
>>> 		# Raise an error if no auth details are given.
>>> @@ -1260,9 +1253,9 @@ class
>>> DDNSProviderLightningWireLabs(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderLoopia(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "loopia.se"
>>> -	name      = "Loopia AB"
>>> -	website   = "https://www.loopia.com"
>>> +	handle = "loopia.se"
>>> +	name = "Loopia AB"
>>> +	website = "https://www.loopia.com"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the HTTP request is to be
>>> found
>>> @@ -1272,9 +1265,9 @@ class DDNSProviderLoopia(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderMyOnlinePortal(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> -	handle    = "myonlineportal.net"
>>> -	name      = "myonlineportal.net"
>>> -	website   = "https:/myonlineportal.net/"
>>> +	handle = "myonlineportal.net"
>>> +	name = "myonlineportal.net"
>>> +	website = "https:/myonlineportal.net/"
>>> 
>>> 	# Information about the request and response can be obtained
>>> here:
>>> 	# https://myonlineportal.net/howto_dyndns
>>> @@ -1283,17 +1276,17 @@ class
>>> DDNSProviderMyOnlinePortal(DDNSProtocolDynDNS2, DDNSProvider):
>>> 
>>> 	def prepare_request_data(self, proto):
>>> 		data = {
>>> -			"hostname" : self.hostname,
>>> -			"ip"     : self.get_address(proto),
>>> +			"hostname": self.hostname,
>>> +			"ip": self.get_address(proto),
>>> 		}
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderNamecheap(DDNSResponseParserXML, DDNSProvider):
>>> -	handle    = "namecheap.com"
>>> -	name      = "Namecheap"
>>> -	website   = "http://namecheap.com"
>>> +	handle = "namecheap.com"
>>> +	name = "Namecheap"
>>> +	website = "http://namecheap.com"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the HTTP request is to be
>>> found
>>> @@ -1311,10 +1304,10 @@ class
>>> DDNSProviderNamecheap(DDNSResponseParserXML, DDNSProvider):
>>> 		address = self.get_address(proto)
>>> 
>>> 		data = {
>>> -			"ip"       : address,
>>> -			"password" : self.password,
>>> -			"host"     : host,
>>> -			"domain"   : domain
>>> +			"ip": address,
>>> +			"password": self.password,
>>> +			"host": host,
>>> +			"domain": domain
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> @@ -1344,9 +1337,9 @@ class
>>> DDNSProviderNamecheap(DDNSResponseParserXML, DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderNOIP(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "no-ip.com"
>>> -	name      = "NoIP"
>>> -	website   = "http://www.noip.com/"
>>> +	handle = "no-ip.com"
>>> +	name = "NoIP"
>>> +	website = "http://www.noip.com/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the HTTP request is to be
>>> found
>>> @@ -1359,17 +1352,17 @@ class DDNSProviderNOIP(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 		assert proto == "ipv4"
>>> 
>>> 		data = {
>>> -			"hostname" : self.hostname,
>>> -			"address"  : self.get_address(proto),
>>> +			"hostname": self.hostname,
>>> +			"address": self.get_address(proto),
>>> 		}
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderNowDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "now-dns.com"
>>> -	name      = "NOW-DNS"
>>> -	website   = "http://now-dns.com/"
>>> +	handle = "now-dns.com"
>>> +	name = "NOW-DNS"
>>> +	website = "http://now-dns.com/"
>>> 	protocols = ("ipv6", "ipv4")
>>> 
>>> 	# Information about the format of the request is to be found
>>> @@ -1380,9 +1373,9 @@ class DDNSProviderNowDNS(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderNsupdateINFO(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "nsupdate.info"
>>> -	name      = "nsupdate.info"
>>> -	website   = "http://nsupdate.info/"
>>> +	handle = "nsupdate.info"
>>> +	name = "nsupdate.info"
>>> +	website = "http://nsupdate.info/"
>>> 	protocols = ("ipv6", "ipv4",)
>>> 
>>> 	# Information about the format of the HTTP request can be found
>>> @@ -1411,16 +1404,16 @@ class
>>> DDNSProviderNsupdateINFO(DDNSProtocolDynDNS2, DDNSProvider):
>>> 
>>> 	def prepare_request_data(self, proto):
>>> 		data = {
>>> -			"myip" : self.get_address(proto),
>>> +			"myip": self.get_address(proto),
>>> 		}
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderOpenDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "opendns.com"
>>> -	name      = "OpenDNS"
>>> -	website   = "http://www.opendns.com"
>>> +	handle = "opendns.com"
>>> +	name = "OpenDNS"
>>> +	website = "http://www.opendns.com"
>>> 
>>> 	# Detailed information about the update request and possible
>>> 	# response codes can be obtained from here:
>>> @@ -1430,17 +1423,17 @@ class
>>> DDNSProviderOpenDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> 
>>> 	def prepare_request_data(self, proto):
>>> 		data = {
>>> -			"hostname" : self.hostname,
>>> -			"myip"     : self.get_address(proto),
>>> +			"hostname": self.hostname,
>>> +			"myip": self.get_address(proto),
>>> 		}
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderOVH(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "ovh.com"
>>> -	name      = "OVH"
>>> -	website   = "http://www.ovh.com/"
>>> +	handle = "ovh.com"
>>> +	name = "OVH"
>>> +	website = "http://www.ovh.com/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# OVH only provides very limited information about how to
>>> @@ -1454,15 +1447,15 @@ class DDNSProviderOVH(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 	def prepare_request_data(self, proto):
>>> 		data = DDNSProtocolDynDNS2.prepare_request_data(self,
>>> proto)
>>> 		data.update({
>>> -			"system" : "dyndns",
>>> +			"system": "dyndns",
>>> 		})
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderRegfish(DDNSProvider):
>>> -	handle  = "regfish.com"
>>> -	name    = "Regfish GmbH"
>>> +	handle = "regfish.com"
>>> +	name = "Regfish GmbH"
>>> 	website = "http://www.regfish.com/"
>>> 
>>> 	# A full documentation to the providers api can be found here
>>> @@ -1474,7 +1467,7 @@ class DDNSProviderRegfish(DDNSProvider):
>>> 
>>> 	def update(self):
>>> 		data = {
>>> -			"fqdn" : self.hostname,
>>> +			"fqdn": self.hostname,
>>> 		}
>>> 
>>> 		# Check if we update an IPv6 address.
>>> @@ -1488,7 +1481,7 @@ class DDNSProviderRegfish(DDNSProvider):
>>> 			data["ipv4"] = address4
>>> 
>>> 		# Raise an error if none address is given.
>>> -		if not data.has_key("ipv6") and not
>>> data.has_key("ipv4"):
>>> +		if "ipv6" not in data and "ipv4" not in data:
>>> 			raise DDNSConfigurationError
>>> 
>>> 		# Check if a token has been set.
>>> @@ -1506,8 +1499,7 @@ class DDNSProviderRegfish(DDNSProvider):
>>> 			response = self.send_request(self.url,
>>> data=data)
>>> 		else:
>>> 			# Send update to the server.
>>> -			response = self.send_request(self.url,
>>> username=self.username, password=self.password,
>>> -				data=data)
>>> +			response = self.send_request(self.url,
>>> username=self.username, password=self.password, data=data)
>>> 
>>> 		# Get the full response message.
>>> 		output = response.read()
>>> @@ -1533,9 +1525,9 @@ class DDNSProviderRegfish(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderSchokokeksDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "schokokeks.org"
>>> -	name      = "Schokokeks"
>>> -	website   = "http://www.schokokeks.org/"
>>> +	handle = "schokokeks.org"
>>> +	name = "Schokokeks"
>>> +	website = "http://www.schokokeks.org/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the format of the request is to be found
>>> @@ -1544,9 +1536,9 @@ class
>>> DDNSProviderSchokokeksDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderSelfhost(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "selfhost.de"
>>> -	name      = "Selfhost.de"
>>> -	website   = "http://www.selfhost.de/"
>>> +	handle = "selfhost.de"
>>> +	name = "Selfhost.de"
>>> +	website = "http://www.selfhost.de/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	url = "https://carol.selfhost.de/nic/update"
>>> @@ -1554,16 +1546,16 @@ class
>>> DDNSProviderSelfhost(DDNSProtocolDynDNS2, DDNSProvider):
>>> 	def prepare_request_data(self, proto):
>>> 		data = DDNSProtocolDynDNS2.prepare_request_data(self,
>>> proto)
>>> 		data.update({
>>> -			"hostname" : "1",
>>> +			"hostname": "1",
>>> 		})
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderServercow(DDNSProvider):
>>> -	handle    = "servercow.de"
>>> -	name      = "servercow.de"
>>> -	website   = "https://servercow.de/"
>>> +	handle = "servercow.de"
>>> +	name = "servercow.de"
>>> +	website = "https://servercow.de/"
>>> 	protocols = ("ipv4", "ipv6")
>>> 
>>> 	url = "https://www.servercow.de/dnsupdate/update.php"
>>> @@ -1571,10 +1563,10 @@ class DDNSProviderServercow(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"ipaddr"   : self.get_address(proto),
>>> -			"hostname" : self.hostname,
>>> -			"username" : self.username,
>>> -			"pass"     : self.password,
>>> +			"ipaddr": self.get_address(proto),
>>> +			"hostname": self.hostname,
>>> +			"username": self.username,
>>> +			"pass": self.password,
>>> 		}
>>> 
>>> 		# Send request to provider
>>> @@ -1596,9 +1588,9 @@ class DDNSProviderServercow(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderSPDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "spdns.org"
>>> -	name      = "SPDYN"
>>> -	website   = "https://www.spdyn.de/"
>>> +	handle = "spdns.org"
>>> +	name = "SPDYN"
>>> +	website = "https://www.spdyn.de/"
>>> 
>>> 	# Detailed information about request and response codes are
>>> provided
>>> 	# by the vendor. They are using almost the same mechanism and
>>> status
>>> @@ -1619,9 +1611,9 @@ class DDNSProviderSPDNS(DDNSProtocolDynDNS2,
>>> DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderStrato(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "strato.com"
>>> -	name      = "Strato AG"
>>> -	website   = "http:/www.strato.com/"
>>> +	handle = "strato.com"
>>> +	name = "Strato AG"
>>> +	website = "http:/www.strato.com/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the request and response can be obtained
>>> here:
>>> @@ -1632,17 +1624,17 @@ class
>>> DDNSProviderStrato(DDNSProtocolDynDNS2, DDNSProvider):
>>> 	def prepare_request_data(self, proto):
>>> 		data = DDNSProtocolDynDNS2.prepare_request_data(self,
>>> proto)
>>> 		data.update({
>>> -			"mx" : "NOCHG",
>>> -			"backupmx" : "NOCHG"
>>> +			"mx": "NOCHG",
>>> +			"backupmx": "NOCHG"
>>> 		})
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderTwoDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "twodns.de"
>>> -	name      = "TwoDNS"
>>> -	website   = "http://www.twodns.de"
>>> +	handle = "twodns.de"
>>> +	name = "TwoDNS"
>>> +	website = "http://www.twodns.de"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Detailed information about the request can be found here
>>> @@ -1655,17 +1647,17 @@ class
>>> DDNSProviderTwoDNS(DDNSProtocolDynDNS2, DDNSProvider):
>>> 		assert proto == "ipv4"
>>> 
>>> 		data = {
>>> -			"ip"       : self.get_address(proto),
>>> -			"hostname" : self.hostname
>>> +			"ip": self.get_address(proto),
>>> +			"hostname": self.hostname
>>> 		}
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderUdmedia(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "udmedia.de"
>>> -	name      = "Udmedia GmbH"
>>> -	website   = "http://www.udmedia.de"
>>> +	handle = "udmedia.de"
>>> +	name = "Udmedia GmbH"
>>> +	website = "http://www.udmedia.de"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Information about the request can be found here
>>> @@ -1675,9 +1667,9 @@ class
>>> DDNSProviderUdmedia(DDNSProtocolDynDNS2, DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderVariomedia(DDNSProtocolDynDNS2, DDNSProvider):
>>> -	handle    = "variomedia.de"
>>> -	name      = "Variomedia"
>>> -	website   = "http://www.variomedia.de/"
>>> +	handle = "variomedia.de"
>>> +	name = "Variomedia"
>>> +	website = "http://www.variomedia.de/"
>>> 	protocols = ("ipv6", "ipv4",)
>>> 
>>> 	# Detailed information about the request can be found here
>>> @@ -1687,29 +1679,29 @@ class
>>> DDNSProviderVariomedia(DDNSProtocolDynDNS2, DDNSProvider):
>>> 
>>> 	def prepare_request_data(self, proto):
>>> 		data = {
>>> -			"hostname" : self.hostname,
>>> -			"myip"     : self.get_address(proto),
>>> +			"hostname": self.hostname,
>>> +			"myip": self.get_address(proto),
>>> 		}
>>> 
>>> 		return data
>>> 
>>> 
>>> class DDNSProviderXLhost(DDNSProtocolDynDNS2, DDNSProvider):
>>> -        handle    = "xlhost.de"
>>> -        name	  = "XLhost"
>>> -        website   = "http://xlhost.de/"
>>> -        protocols = ("ipv4",)
>>> +	handle = "xlhost.de"
>>> +	name = "XLhost"
>>> +	website = "http://xlhost.de/"
>>> +	protocols = ("ipv4",)
>>> 
>>> -        # Information about the format of the HTTP request is to
>>> be found
>>> -        # here: 
>>> https://xlhost.de/faq/index_html?topicId=CQA2ELIPO4SQ
>>> +	# Information about the format of the HTTP request is to be
>>> found
>>> +	# here: https://xlhost.de/faq/index_html?topicId=CQA2ELIPO4SQ
>>> 
>>> -        url = "https://nsupdate.xlhost.de/"
>>> +	url = "https://nsupdate.xlhost.de/"
>>> 
>>> 
>>> class DDNSProviderZoneedit(DDNSProvider):
>>> -	handle    = "zoneedit.com"
>>> -	name      = "Zoneedit"
>>> -	website   = "http://www.zoneedit.com"
>>> +	handle = "zoneedit.com"
>>> +	name = "Zoneedit"
>>> +	website = "http://www.zoneedit.com"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# Detailed information about the request and the response codes
>>> can be
>>> @@ -1721,13 +1713,12 @@ class DDNSProviderZoneedit(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"dnsto" : self.get_address(proto),
>>> -			"host"  : self.hostname
>>> +			"dnsto": self.get_address(proto),
>>> +			"host": self.hostname
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> -		response = self.send_request(self.url,
>>> username=self.username, password=self.password,
>>> -			data=data)
>>> +		response = self.send_request(self.url,
>>> username=self.username, password=self.password, data=data)
>>> 
>>> 		# Get the full response message.
>>> 		output = response.read()
>>> @@ -1749,9 +1740,9 @@ class DDNSProviderZoneedit(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderDNSmadeEasy(DDNSProvider):
>>> -	handle    = "dnsmadeeasy.com"
>>> -	name      = "DNSmadeEasy.com"
>>> -	website   = "http://www.dnsmadeeasy.com/"
>>> +	handle = "dnsmadeeasy.com"
>>> +	name = "DNSmadeEasy.com"
>>> +	website = "http://www.dnsmadeeasy.com/"
>>> 	protocols = ("ipv4",)
>>> 
>>> 	# DNS Made Easy Nameserver Provider also offering Dynamic DNS
>>> @@ -1763,10 +1754,10 @@ class
>>> DDNSProviderDNSmadeEasy(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"ip" : self.get_address(proto),
>>> -			"id" : self.hostname,
>>> -			"username" : self.username,
>>> -			"password" : self.password,
>>> +			"ip": self.get_address(proto),
>>> +			"id": self.hostname,
>>> +			"username": self.username,
>>> +			"password": self.password,
>>> 		}
>>> 
>>> 		# Send update to the server.
>>> @@ -1797,9 +1788,9 @@ class DDNSProviderDNSmadeEasy(DDNSProvider):
>>> 
>>> 
>>> class DDNSProviderZZZZ(DDNSProvider):
>>> -	handle    = "zzzz.io"
>>> -	name      = "zzzz"
>>> -	website   = "https://zzzz.io"
>>> +	handle = "zzzz.io"
>>> +	name = "zzzz"
>>> +	website = "https://zzzz.io"
>>> 	protocols = ("ipv6", "ipv4",)
>>> 
>>> 	# Detailed information about the update request can be found
>>> here:
>>> @@ -1813,8 +1804,8 @@ class DDNSProviderZZZZ(DDNSProvider):
>>> 
>>> 	def update_protocol(self, proto):
>>> 		data = {
>>> -			"ip"    : self.get_address(proto),
>>> -			"token" : self.token,
>>> +			"ip": self.get_address(proto),
>>> +			"token": self.token,
>>> 		}
>>> 
>>> 		if proto == "ipv6":
>>> diff --git a/src/ddns/system.py b/src/ddns/system.py
>>> index b7a51f6..59c0525 100644
>>> --- a/src/ddns/system.py
>>> +++ b/src/ddns/system.py
>>> @@ -1,8 +1,8 @@
>>> -#!/usr/bin/python
>>> +#!/usr/bin/python3
>>> ###################################################################
>>> ############
>>> #
>>> 
>>>         #
>>> # ddns - A dynamic DNS client for IPFire
>>>                                     #
>>> -# Copyright (C) 2012 IPFire development team
>>>                                 #
>>> +# Copyright (C) 2012-2019 IPFire development team
>>>                            #
>>> #
>>> 
>>>         #
>>> # This program is free software: you can redistribute it and/or
>>> modify        #
>>> # it under the terms of the GNU General Public License as published
>>> by        #
>>> @@ -23,18 +23,20 @@ import base64
>>> import re
>>> import ssl
>>> import socket
>>> -import urllib
>>> -import urllib2
>>> +import urllib.request
>>> +import urllib.parse
>>> +import urllib.error
>>> 
>>> -from __version__ import CLIENT_VERSION
>>> +from .__version__ import CLIENT_VERSION
>>> from .errors import *
>>> -from i18n import _
>>> +from .i18n import _
>>> 
>>> # Initialize the logger.
>>> import logging
>>> logger = logging.getLogger("ddns.system")
>>> logger.propagate = 1
>>> 
>>> +
>>> class DDNSSystem(object):
>>> 	"""
>>> 		The DDNSSystem class adds a layer of abstraction
>>> @@ -79,7 +81,7 @@ class DDNSSystem(object):
>>> 				with open("/var/ipfire/red/local-
>>> ipaddress") as f:
>>> 					return f.readline()
>>> 
>>> -			except IOError, e:
>>> +			except IOError as e:
>>> 				# File not found
>>> 				if e.errno == 2:
>>> 					return
>>> @@ -137,7 +139,7 @@ class DDNSSystem(object):
>>> 		if data:
>>> 			logger.debug("  data: %s" % data)
>>> 
>>> -		req = urllib2.Request(url, data=data)
>>> +		req = urllib.request.Request(url, data=data)
>>> 
>>> 		if username and password:
>>> 			basic_auth_header =
>>> self._make_basic_auth_header(username, password)
>>> @@ -159,24 +161,24 @@ class DDNSSystem(object):
>>> 		assert req.get_method() == method
>>> 
>>> 		logger.debug(_("Request header:"))
>>> -		for k, v in req.headers.items():
>>> +		for k, v in list(req.headers.items()):
>>> 			logger.debug("  %s: %s" % (k, v))
>>> 
>>> 		try:
>>> -			resp = urllib2.urlopen(req, timeout=timeout)
>>> +			resp = urllib.request.urlopen(req,
>>> timeout=timeout)
>>> 
>>> 			# Log response header.
>>> 			logger.debug(_("Response header (Status Code
>>> %s):") % resp.code)
>>> -			for k, v in resp.info().items():
>>> +			for k, v in list(resp.info().items()):
>>> 				logger.debug("  %s: %s" % (k, v))
>>> 
>>> 			# Return the entire response object.
>>> 			return resp
>>> 
>>> -		except urllib2.HTTPError, e:
>>> +		except urllib.error.HTTPError as e:
>>> 			# Log response header.
>>> 			logger.debug(_("Response header (Status Code
>>> %s):") % e.code)
>>> -			for k, v in e.hdrs.items():
>>> +			for k, v in list(e.hdrs.items()):
>>> 				logger.debug("  %s: %s" % (k, v))
>>> 
>>> 			# 400 - Bad request
>>> @@ -209,7 +211,7 @@ class DDNSSystem(object):
>>> 			# Raise all other unhandled exceptions.
>>> 			raise
>>> 
>>> -		except urllib2.URLError, e:
>>> +		except urllib.error.URLError as e:
>>> 			if e.reason:
>>> 				# Handle SSL errors
>>> 				if isinstance(e.reason, ssl.SSLError):
>>> @@ -240,7 +242,7 @@ class DDNSSystem(object):
>>> 			# Raise all other unhandled exceptions.
>>> 			raise
>>> 
>>> -		except socket.timeout, e:
>>> +		except socket.timeout as e:
>>> 			logger.debug(_("Connection timeout"))
>>> 
>>> 			raise DDNSConnectionTimeoutError
>>> @@ -248,8 +250,8 @@ class DDNSSystem(object):
>>> 	def _format_query_args(self, data):
>>> 		args = []
>>> 
>>> -		for k, v in data.items():
>>> -			arg = "%s=%s" % (k, urllib.quote(v))
>>> +		for k, v in list(data.items()):
>>> +			arg = "%s=%s" % (k, urllib.parse.quote(v))
>>> 			args.append(arg)
>>> 
>>> 		return "&".join(args)
>>> @@ -258,7 +260,7 @@ class DDNSSystem(object):
>>> 		authstring = "%s:%s" % (username, password)
>>> 
>>> 		# Encode authorization data in base64.
>>> -		authstring = base64.encodestring(authstring)
>>> +		authstring = base64.encodebytes(authstring)
>>> 
>>> 		# Remove any newline characters.
>>> 		authstring = authstring.replace("\n", "")
>>> @@ -354,7 +356,7 @@ class DDNSSystem(object):
>>> 		# Resolve the host address.
>>> 		try:
>>> 			response = socket.getaddrinfo(hostname, None,
>>> family)
>>> -		except socket.gaierror, e:
>>> +		except socket.gaierror as e:
>>> 			# Name or service not known
>>> 			if e.errno == -2:
>>> 				return []
>>> @@ -418,7 +420,7 @@ class DDNSSystem(object):
>>> 		"""
>>> 		try:
>>> 			f = open("/etc/os-release", "r")
>>> -		except IOError, e:
>>> +		except IOError as e:
>>> 			# File not found
>>> 			if e.errno == 2:
>>> 				return
>>> @@ -447,7 +449,7 @@ class DDNSSystem(object):
>>> 		"""
>>> 		try:
>>> 			f = open("/etc/system-release", "r")
>>> -		except IOError, e:
>>> +		except IOError as e:
>>> 			# File not found
>>> 			if e.errno == 2:
>>> 				return
>>> -- 
>>> 2.24.1
>> 
>> This patch is very very long and does not need to be.
>> 
>> There should be no changes in the code styling and all those empty
>> lines that are being added make the code messy.
>> 
>> Please remove them, cleanup the patch and submit again.
>> 
>> Best,
>> -Michael
>> 
>>> 
>>> 
>>> _______________________________________________
>>> ddns mailing list
>>> ddns(a)lists.ipfire.org
>>> https://lists.ipfire.org/mailman/listinfo/ddns
>> 
>> _______________________________________________
>> ddns mailing list
>> ddns(a)lists.ipfire.org
>> https://lists.ipfire.org/mailman/listinfo/ddns
> _______________________________________________
> ddns mailing list
> ddns(a)lists.ipfire.org
> https://lists.ipfire.org/mailman/listinfo/ddns


  reply	other threads:[~2020-01-06 14:44 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <C6E3B0A6-0514-498E-858B-EA48C9E162AF@ipfire.org>
2020-01-06 12:31 ` Stefan Schantl
2020-01-06 14:44   ` Michael Tremer [this message]
     [not found] <29BE055B-AC06-45CB-BF63-D344E2DEC6A9@ipfire.org>
2019-12-25 15:39 ` Kim
2019-12-25 15:52   ` Michael Tremer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=B338545A-3BC9-4B87-B834-9895A0279F90@ipfire.org \
    --to=michael.tremer@ipfire.org \
    --cc=ddns@lists.ipfire.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox