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@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@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@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@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@lists.ipfire.org
https://lists.ipfire.org/mailman/listinfo/ddns